Refactor odfeditor plugin so it works without temp files (#4307)
- Update WebODF to 0.5.4 (with compressed responses support) - Don't use temporary files for better security and multi-server scenarious support
This commit is contained in:
parent
79e07cc1d6
commit
6bbad6f15e
9 changed files with 1225 additions and 2066 deletions
|
@ -1,43 +1,67 @@
|
|||
/**
|
||||
* @license
|
||||
* Copyright (C) 2012 KO GmbH <copyright@kogmbh.com>
|
||||
*
|
||||
* @licstart
|
||||
* The JavaScript code in this page is free software: you can redistribute it
|
||||
* and/or modify it under the terms of the GNU Affero General Public License
|
||||
* (GNU AGPL) as published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version. The code is distributed
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU AGPL for more details.
|
||||
* This file is part of WebODF.
|
||||
*
|
||||
* As additional permission under GNU AGPL version 3 section 7, you
|
||||
* may distribute non-source (e.g., minimized or compacted) forms of
|
||||
* that code without the copy of the GNU GPL normally required by
|
||||
* section 4, provided you include this license notice and a URL
|
||||
* through which recipients can access the Corresponding Source.
|
||||
* WebODF is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Affero General Public License (GNU AGPL)
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* As a special exception to the AGPL, any HTML file which merely makes function
|
||||
* calls to this code, and for that purpose includes it by reference shall be
|
||||
* deemed a separate work for copyright law purposes. In addition, the copyright
|
||||
* holders of this code give you permission to combine this code with free
|
||||
* software libraries that are released under the GNU LGPL. You may copy and
|
||||
* distribute such a system following the terms of the GNU AGPL for this code
|
||||
* and the LGPL for the libraries. If you modify this code, you may extend this
|
||||
* exception to your version of the code, but you are not obligated to do so.
|
||||
* If you do not wish to do so, delete this exception statement from your
|
||||
* version.
|
||||
* WebODF is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* This license applies to this entire compilation.
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with WebODF. If not, see <http://www.gnu.org/licenses/>.
|
||||
* @licend
|
||||
*
|
||||
* @source: http://www.webodf.org/
|
||||
* @source: http://gitorious.org/webodf/webodf/
|
||||
* @source: https://github.com/kogmbh/WebODF/
|
||||
*/
|
||||
|
||||
/*global runtime, document, odf, console*/
|
||||
/*global runtime, document, odf, gui, console, webodf*/
|
||||
|
||||
function ODFViewerPlugin() {
|
||||
"use strict";
|
||||
|
||||
function init(callback) {
|
||||
/*
|
||||
var lib = document.createElement('script'),
|
||||
pluginCSS;
|
||||
|
||||
lib.async = false;
|
||||
lib.src = './webodf.js';
|
||||
lib.type = 'text/javascript';
|
||||
lib.onload = function () {
|
||||
*/
|
||||
runtime.loadClass('gui.HyperlinkClickHandler');
|
||||
runtime.loadClass('odf.OdfCanvas');
|
||||
runtime.loadClass('ops.Session');
|
||||
runtime.loadClass('gui.CaretManager');
|
||||
runtime.loadClass("gui.HyperlinkTooltipView");
|
||||
runtime.loadClass('gui.SessionController');
|
||||
runtime.loadClass('gui.SvgSelectionView');
|
||||
runtime.loadClass('gui.SelectionViewManager');
|
||||
runtime.loadClass('gui.ShadowCursor');
|
||||
runtime.loadClass('gui.SessionView');
|
||||
|
||||
callback();
|
||||
/*
|
||||
};
|
||||
|
||||
document.getElementsByTagName('head')[0].appendChild(lib);
|
||||
|
||||
pluginCSS = document.createElement('link');
|
||||
pluginCSS.setAttribute("rel", "stylesheet");
|
||||
pluginCSS.setAttribute("type", "text/css");
|
||||
pluginCSS.setAttribute("href", "./ODFViewerPlugin.css");
|
||||
document.head.appendChild(pluginCSS);
|
||||
*/
|
||||
}
|
||||
|
||||
// that should probably be provided by webodf
|
||||
function nsResolver(prefix) {
|
||||
var ns = {
|
||||
|
@ -50,6 +74,8 @@ function ODFViewerPlugin() {
|
|||
}
|
||||
|
||||
var self = this,
|
||||
pluginName = "WebODF",
|
||||
pluginURL = "http://webodf.org",
|
||||
odfCanvas = null,
|
||||
odfElement = null,
|
||||
initialized = false,
|
||||
|
@ -59,18 +85,61 @@ function ODFViewerPlugin() {
|
|||
currentPage = null;
|
||||
|
||||
this.initialize = function (viewerElement, documentUrl) {
|
||||
odfElement = document.getElementById('canvas');
|
||||
odfCanvas = new odf.OdfCanvas(odfElement);
|
||||
odfCanvas.load(documentUrl);
|
||||
// If the URL has a fragment (#...), try to load the file it represents
|
||||
init(function () {
|
||||
var session,
|
||||
sessionController,
|
||||
sessionView,
|
||||
odtDocument,
|
||||
shadowCursor,
|
||||
selectionViewManager,
|
||||
caretManager,
|
||||
localMemberId = 'localuser',
|
||||
hyperlinkTooltipView,
|
||||
eventManager;
|
||||
|
||||
odfCanvas.addListener('statereadychange', function () {
|
||||
root = odfCanvas.odfContainer().rootElement;
|
||||
initialized = true;
|
||||
documentType = odfCanvas.odfContainer().getDocumentType(root);
|
||||
if (documentType === 'text' && odfCanvas.enableAnnotations) {
|
||||
odfCanvas.enableAnnotations(true);
|
||||
}
|
||||
self.onLoad();
|
||||
odfElement = document.getElementById('canvas');
|
||||
odfCanvas = new odf.OdfCanvas(odfElement);
|
||||
odfCanvas.load(documentUrl);
|
||||
|
||||
odfCanvas.addListener('statereadychange', function () {
|
||||
root = odfCanvas.odfContainer().rootElement;
|
||||
initialized = true;
|
||||
documentType = odfCanvas.odfContainer().getDocumentType(root);
|
||||
|
||||
if (documentType === 'text') {
|
||||
odfCanvas.enableAnnotations(true, false);
|
||||
|
||||
session = new ops.Session(odfCanvas);
|
||||
odtDocument = session.getOdtDocument();
|
||||
shadowCursor = new gui.ShadowCursor(odtDocument);
|
||||
sessionController = new gui.SessionController(session, localMemberId, shadowCursor, {});
|
||||
eventManager = sessionController.getEventManager();
|
||||
caretManager = new gui.CaretManager(sessionController, odfCanvas.getViewport());
|
||||
selectionViewManager = new gui.SelectionViewManager(gui.SvgSelectionView);
|
||||
sessionView = new gui.SessionView({
|
||||
caretAvatarsInitiallyVisible: false
|
||||
}, localMemberId, session, sessionController.getSessionConstraints(), caretManager, selectionViewManager);
|
||||
selectionViewManager.registerCursor(shadowCursor);
|
||||
hyperlinkTooltipView = new gui.HyperlinkTooltipView(odfCanvas,
|
||||
sessionController.getHyperlinkClickHandler().getModifier);
|
||||
eventManager.subscribe("mousemove", hyperlinkTooltipView.showTooltip);
|
||||
eventManager.subscribe("mouseout", hyperlinkTooltipView.hideTooltip);
|
||||
|
||||
var op = new ops.OpAddMember();
|
||||
op.init({
|
||||
memberid: localMemberId,
|
||||
setProperties: {
|
||||
fillName: runtime.tr("Unknown Author"),
|
||||
color: "blue"
|
||||
}
|
||||
});
|
||||
session.enqueue([op]);
|
||||
sessionController.insertLocalCursor();
|
||||
}
|
||||
|
||||
self.onLoad();
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -133,4 +202,23 @@ function ODFViewerPlugin() {
|
|||
odfCanvas.showPage(n);
|
||||
};
|
||||
|
||||
this.getPluginName = function () {
|
||||
return pluginName;
|
||||
};
|
||||
|
||||
this.getPluginVersion = function () {
|
||||
var version;
|
||||
|
||||
if (String(typeof webodf) !== "undefined") {
|
||||
version = webodf.Version;
|
||||
} else {
|
||||
version = "Unknown";
|
||||
}
|
||||
|
||||
return version;
|
||||
};
|
||||
|
||||
this.getPluginURL = function () {
|
||||
return pluginURL;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -6,11 +6,5 @@ by Tobias Hintze. See http://webodf.org for more information.
|
|||
|
||||
INSTALLATION
|
||||
------------
|
||||
Make the the folder 'files' in this directory writeable for the webserver.
|
||||
It is used to temporarily store attachment files. Also make sure in the
|
||||
webserver configuraton that this directory is not browsable. For Apache
|
||||
webservers the included .htaccess file should already do the job.
|
||||
|
||||
Add 'odfviewer' to the list of plugins in the config/main.inc.php file
|
||||
of your Roundcube installation.
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
"description": "Open Document Viewer plugin",
|
||||
"homepage": "http://git.kolab.org/roundcubemail-plugins-kolab/",
|
||||
"license": "AGPLv3",
|
||||
"version": "3.2.3",
|
||||
"version": "3.3.0",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Thomas Bruederli",
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
<IfModule mod_deflate.c>
|
||||
SetOutputFilter NONE
|
||||
</IfModule>
|
||||
|
||||
Options -Indexes
|
|
@ -1,11 +1,13 @@
|
|||
<!DOCTYPE html>
|
||||
<html dir="ltr" lang="en-US">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"></meta>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0"/>
|
||||
<title>Roundcube WebODF Viewer</title>
|
||||
<link rel="stylesheet" type="text/css" href="%%DOCROOT%%viewer.css"/>
|
||||
<script type="text/javascript" src="%%DOCROOT%%viewer.js" charset="utf-8"></script>
|
||||
<script type="text/javascript" src="%%DOCROOT%%ODFViewerPlugin.js" charset="utf-8"></script>
|
||||
<script type="text/javascript" src="%%DOCROOT%%webodf.js" charset="utf-8"></script>
|
||||
<link rel="stylesheet" type="text/css" href="%%viewer.css%%"/>
|
||||
<script type="text/javascript" src="%%viewer.js%%" charset="utf-8"></script>
|
||||
<script type="text/javascript" src="%%ODFViewerPlugin.js%%" charset="utf-8"></script>
|
||||
<script type="text/javascript" src="%%webodf.js%%" charset="utf-8"></script>
|
||||
<script type="text/javascript" charset="utf-8">
|
||||
|
||||
/**
|
||||
|
@ -33,74 +35,74 @@
|
|||
|
||||
*/
|
||||
|
||||
function init() {
|
||||
viewer = new Viewer(new ODFViewerPlugin(), '%%DOCURL%%');
|
||||
}
|
||||
window.setTimeout(init, 0);
|
||||
window.onload = function () {
|
||||
var viewer = new Viewer(new ODFViewerPlugin(), %%PARAMS%%);
|
||||
};
|
||||
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="viewer">
|
||||
<div id="titlebar">
|
||||
<div id="documentName"></div>
|
||||
<div id="toolbarRight">
|
||||
<button id="presentation" class="toolbarButton presentation" title="Presentation"></button>
|
||||
<button id="fullscreen" class="toolbarButton fullscreen" title="Fullscreen"></button>
|
||||
<button id="download" class="toolbarButton download" title="Download"></button>
|
||||
</div>
|
||||
</div>
|
||||
<div id="toolbarContainer">
|
||||
<div id="toolbar">
|
||||
<div id="toolbarLeft">
|
||||
<div id="navButtons" class="splitToolbarButton">
|
||||
<button id="previous" class="toolbarButton pageUp" title="Previous Page"></button>
|
||||
<div class="splitToolbarButtonSeparator"></div>
|
||||
<button id="next" class="toolbarButton pageDown" title="Next Page"></button>
|
||||
</div>
|
||||
<label id="pageNumberLabel" class="toolbarLabel" for="pageNumber">Page:</label>
|
||||
<input type="number" id="pageNumber" class="toolbarField pageNumber"></input>
|
||||
<span id="numPages" class="toolbarLabel"></span>
|
||||
<div id="viewer">
|
||||
<div id="titlebar">
|
||||
<div id="documentName"></div>
|
||||
<div id="toolbarRight">
|
||||
<button id="presentation" class="toolbarButton presentation" title="Presentation"></button>
|
||||
<button id="fullscreen" class="toolbarButton fullscreen" title="Fullscreen"></button>
|
||||
<button id="download" class="toolbarButton download" title="Download"></button>
|
||||
</div>
|
||||
<div id="toolbarMiddleContainer" class="outerCenter">
|
||||
<div id="toolbarMiddle" class="innerCenter">
|
||||
<div id = 'zoomButtons' class="splitToolbarButton">
|
||||
<button id="zoomOut" class="toolbarButton zoomOut" title="Zoom Out"></button>
|
||||
</div>
|
||||
<div id="toolbarContainer">
|
||||
<div id="toolbar">
|
||||
<div id="toolbarLeft">
|
||||
<div id="navButtons" class="splitToolbarButton">
|
||||
<button id="previous" class="toolbarButton pageUp" title="Previous Page"></button>
|
||||
<div class="splitToolbarButtonSeparator"></div>
|
||||
<button id="zoomIn" class="toolbarButton zoomIn" title="Zoom In"></button>
|
||||
<button id="next" class="toolbarButton pageDown" title="Next Page"></button>
|
||||
</div>
|
||||
<span id="scaleSelectContainer" class="dropdownToolbarButton">
|
||||
<select id="scaleSelect" title="Zoom" oncontextmenu="return false;">
|
||||
<option id="pageAutoOption" value="auto" selected>Automatic</option>
|
||||
<option id="pageActualOption" value="page-actual">Actual Size</option>
|
||||
<option id="pageWidthOption" value="page-width">Full Width</option>
|
||||
<option id="customScaleOption" value="custom"></option>
|
||||
<option value="0.5">50%</option>
|
||||
<option value="0.75">75%</option>
|
||||
<option value="1">100%</option>
|
||||
<option value="1.25">125%</option>
|
||||
<option value="1.5">150%</option>
|
||||
<option value="2">200%</option>
|
||||
</select>
|
||||
</span>
|
||||
<div id="sliderContainer">
|
||||
<div id="slider"></div>
|
||||
<label id="pageNumberLabel" class="toolbarLabel" for="pageNumber">Page:</label>
|
||||
<input type="number" id="pageNumber" class="toolbarField pageNumber"/>
|
||||
<span id="numPages" class="toolbarLabel"></span>
|
||||
</div>
|
||||
<div id="toolbarMiddleContainer" class="outerCenter">
|
||||
<div id="toolbarMiddle" class="innerCenter">
|
||||
<div id = 'zoomButtons' class="splitToolbarButton">
|
||||
<button id="zoomOut" class="toolbarButton zoomOut" title="Zoom Out"></button>
|
||||
<div class="splitToolbarButtonSeparator"></div>
|
||||
<button id="zoomIn" class="toolbarButton zoomIn" title="Zoom In"></button>
|
||||
</div>
|
||||
<span id="scaleSelectContainer" class="dropdownToolbarButton">
|
||||
<select id="scaleSelect" title="Zoom" oncontextmenu="return false;">
|
||||
<option id="pageAutoOption" value="auto" selected>Automatic</option>
|
||||
<option id="pageActualOption" value="page-actual">Actual Size</option>
|
||||
<option id="pageWidthOption" value="page-width">Full Width</option>
|
||||
<option id="customScaleOption" value="custom"> </option>
|
||||
<option value="0.5">50%</option>
|
||||
<option value="0.75">75%</option>
|
||||
<option value="1">100%</option>
|
||||
<option value="1.25">125%</option>
|
||||
<option value="1.5">150%</option>
|
||||
<option value="2">200%</option>
|
||||
</select>
|
||||
</span>
|
||||
<div id="sliderContainer">
|
||||
<div id="slider"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="canvasContainer">
|
||||
<div id="canvas"></div>
|
||||
</div>
|
||||
<div id="overlayNavigator">
|
||||
<div id="previousPage"></div>
|
||||
<div id="nextPage"></div>
|
||||
</div>
|
||||
<div id="overlayCloseButton">
|
||||
✖
|
||||
</div>
|
||||
<div id="dialogOverlay"></div>
|
||||
<div id="blanked"></div>
|
||||
</div>
|
||||
<div id="canvasContainer">
|
||||
<div id="canvas"></div>
|
||||
</div>
|
||||
<div id="overlayNavigator">
|
||||
<div id="previousPage"></div>
|
||||
<div id="nextPage"></div>
|
||||
</div>
|
||||
<div id="overlayCloseButton">
|
||||
✖
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -26,132 +26,84 @@
|
|||
*/
|
||||
class odfviewer extends rcube_plugin
|
||||
{
|
||||
public $task = 'mail|calendar|tasks|logout';
|
||||
public $task = 'mail|calendar|tasks';
|
||||
|
||||
private $tempdir = 'plugins/odfviewer/files/';
|
||||
private $tempbase = 'plugins/odfviewer/files/';
|
||||
private $odf_mimetypes = array(
|
||||
'application/vnd.oasis.opendocument.chart',
|
||||
'application/vnd.oasis.opendocument.chart-template',
|
||||
'application/vnd.oasis.opendocument.formula',
|
||||
'application/vnd.oasis.opendocument.formula-template',
|
||||
'application/vnd.oasis.opendocument.graphics',
|
||||
'application/vnd.oasis.opendocument.graphics-template',
|
||||
'application/vnd.oasis.opendocument.presentation',
|
||||
'application/vnd.oasis.opendocument.presentation-template',
|
||||
'application/vnd.oasis.opendocument.text',
|
||||
'application/vnd.oasis.opendocument.text-master',
|
||||
'application/vnd.oasis.opendocument.text-template',
|
||||
'application/vnd.oasis.opendocument.spreadsheet',
|
||||
'application/vnd.oasis.opendocument.spreadsheet-template',
|
||||
);
|
||||
|
||||
private $odf_mimetypes = array(
|
||||
'application/vnd.oasis.opendocument.chart',
|
||||
'application/vnd.oasis.opendocument.chart-template',
|
||||
'application/vnd.oasis.opendocument.formula',
|
||||
'application/vnd.oasis.opendocument.formula-template',
|
||||
'application/vnd.oasis.opendocument.graphics',
|
||||
'application/vnd.oasis.opendocument.graphics-template',
|
||||
'application/vnd.oasis.opendocument.presentation',
|
||||
'application/vnd.oasis.opendocument.presentation-template',
|
||||
'application/vnd.oasis.opendocument.text',
|
||||
'application/vnd.oasis.opendocument.text-master',
|
||||
'application/vnd.oasis.opendocument.text-template',
|
||||
'application/vnd.oasis.opendocument.spreadsheet',
|
||||
'application/vnd.oasis.opendocument.spreadsheet-template',
|
||||
);
|
||||
function init()
|
||||
{
|
||||
// webODF only supports IE9 or higher
|
||||
$ua = new rcube_browser;
|
||||
if ($ua->ie && $ua->ver < 9) {
|
||||
return;
|
||||
}
|
||||
|
||||
function init()
|
||||
{
|
||||
$this->tempdir = $this->home . '/files/';
|
||||
$this->tempbase = $this->urlbase . 'files/';
|
||||
|
||||
// webODF only supports IE9 or higher
|
||||
$ua = new rcube_browser;
|
||||
if ($ua->ie && $ua->ver < 9)
|
||||
return;
|
||||
// extend list of mimetypes that should open in preview
|
||||
$rcmail = rcube::get_instance();
|
||||
if ($rcmail->action == 'preview' || $rcmail->action == 'show' || $rcmail->task == 'calendar' || $rcmail->task == 'tasks') {
|
||||
$mimetypes = (array)$rcmail->config->get('client_mimetypes');
|
||||
$rcmail->config->set('client_mimetypes', array_merge($mimetypes, $this->odf_mimetypes));
|
||||
}
|
||||
|
||||
$this->add_hook('message_part_get', array($this, 'get_part'));
|
||||
$this->add_hook('session_destroy', array($this, 'session_cleanup'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler for message attachment download
|
||||
*/
|
||||
function get_part($args)
|
||||
{
|
||||
if (!$args['download'] && $args['mimetype'] && in_array($args['mimetype'], $this->odf_mimetypes)) {
|
||||
if (empty($_GET['_load'])) {
|
||||
// extend list of mimetypes that should open in preview
|
||||
$rcmail = rcube::get_instance();
|
||||
$exts = rcube_mime::get_mime_extensions($args['mimetype']);
|
||||
$suffix = $exts ? '.'.$exts[0] : '.odt';
|
||||
$fn = md5(session_id() . $_SERVER['REQUEST_URI']) . $suffix;
|
||||
|
||||
// FIXME: copy file to disk because only apache can send the file correctly
|
||||
$tempfn = $this->tempdir . $fn;
|
||||
if (!file_exists($tempfn)) {
|
||||
if ($args['body']) {
|
||||
file_put_contents($tempfn, $args['body']);
|
||||
}
|
||||
else {
|
||||
$fp = fopen($tempfn, 'w');
|
||||
$imap = rcube::get_instance()->get_storage();
|
||||
$imap->get_message_part($args['uid'], $args['id'], $args['part'], false, $fp);
|
||||
fclose($fp);
|
||||
}
|
||||
|
||||
// remember tempfiles in session to clean up on logout
|
||||
$_SESSION['odfviewer']['tempfiles'][] = $fn;
|
||||
if ($rcmail->action == 'preview' || $rcmail->action == 'show' || $rcmail->task == 'calendar' || $rcmail->task == 'tasks') {
|
||||
$mimetypes = (array)$rcmail->config->get('client_mimetypes');
|
||||
$rcmail->config->set('client_mimetypes', array_merge($mimetypes, $this->odf_mimetypes));
|
||||
}
|
||||
|
||||
// send webODF viewer page
|
||||
$html = file_get_contents($this->home . '/odf.html');
|
||||
header("Content-Type: text/html; charset=" . RCMAIL_CHARSET);
|
||||
echo strtr($html, array(
|
||||
'%%DOCROOT%%' => $rcmail->output->asset_url($this->urlbase),
|
||||
'%%DOCURL%%' => $rcmail->output->asset_url($this->tempbase . $fn), # $_SERVER['REQUEST_URI'].'&_load=1',
|
||||
));
|
||||
$args['abort'] = true;
|
||||
}
|
||||
/*
|
||||
else {
|
||||
if ($_SERVER['REQUEST_METHOD'] == 'HEAD') {
|
||||
header("Content-Length: " . max(10, $args['part']->size)); # content-length has to be present
|
||||
$args['body'] = ' '; # send empty body
|
||||
return $args;
|
||||
$this->add_hook('message_part_get', array($this, 'get_part'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler for message attachment download
|
||||
*/
|
||||
function get_part($args)
|
||||
{
|
||||
if (!$args['download'] && $args['mimetype'] && in_array($args['mimetype'], $this->odf_mimetypes)) {
|
||||
$rcmail = rcube::get_instance();
|
||||
$params = array(
|
||||
'documentUrl' => $_SERVER['REQUEST_URI'] . '&_download=1',
|
||||
'filename' => $args['part']->filename ?: 'file.odt',
|
||||
'type' => $args['mimetype'],
|
||||
);
|
||||
|
||||
// send webODF viewer page
|
||||
$html = file_get_contents($this->home . '/odf.html');
|
||||
header("Content-Type: text/html; charset=" . RCMAIL_CHARSET);
|
||||
echo strtr($html, array(
|
||||
'%%PARAMS%%' => rcube_output::json_serialize($params),
|
||||
'%%viewer.css%%' => $this->asset_path('viewer.css'),
|
||||
'%%viewer.js%%' => $this->asset_path('viewer.js'),
|
||||
'%%ODFViewerPlugin.js%%' => $this->asset_path('ODFViewerPlugin.js'),
|
||||
'%%webodf.js%%' => $this->asset_path('webodf.js'),
|
||||
));
|
||||
|
||||
$args['abort'] = true;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
return $args;
|
||||
}
|
||||
|
||||
return $args;
|
||||
}
|
||||
private function asset_path($path)
|
||||
{
|
||||
$rcmail = rcube::get_instance();
|
||||
$assets_dir = $rcmail->config->get('assets_dir');
|
||||
|
||||
/**
|
||||
* Remove temp files opened during this session
|
||||
*/
|
||||
function session_cleanup()
|
||||
{
|
||||
foreach ((array)$_SESSION['odfviewer']['tempfiles'] as $fn) {
|
||||
@unlink($this->tempdir . $fn);
|
||||
$mtime = filemtime($this->home . '/' . $path);
|
||||
if (!$mtime && $assets_dir) {
|
||||
$mtime = filemtime($assets_dir . '/plugins/odfviewer/' . $path);
|
||||
}
|
||||
|
||||
$path = $this->urlbase . $path . ($mtime ? '?s=' . $mtime : '');
|
||||
|
||||
return $rcmail->output->asset_url($path);
|
||||
}
|
||||
|
||||
// also trigger general garbage collection because not everybody logs out properly
|
||||
$this->gc_cleanup();
|
||||
}
|
||||
|
||||
/**
|
||||
* Garbage collector function for temp files.
|
||||
* Remove temp files older than two days
|
||||
*/
|
||||
function gc_cleanup()
|
||||
{
|
||||
$tmp = unslashify($this->tempdir);
|
||||
$expire = mktime() - 172800; // expire in 48 hours
|
||||
|
||||
if ($dir = opendir($tmp)) {
|
||||
while (($fname = readdir($dir)) !== false) {
|
||||
if ($fname[0] == '.')
|
||||
continue;
|
||||
|
||||
if (filemtime($tmp.'/'.$fname) < $expire)
|
||||
@unlink($tmp.'/'.$fname);
|
||||
}
|
||||
|
||||
closedir($dir);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,41 +1,50 @@
|
|||
/**
|
||||
* @license
|
||||
* Copyright (C) 2013 KO GmbH <copyright@kogmbh.com>
|
||||
* Copyright (C) 2012-2015 KO GmbH <copyright@kogmbh.com>
|
||||
*
|
||||
* @licstart
|
||||
* The JavaScript code in this page is free software: you can redistribute it
|
||||
* and/or modify it under the terms of the GNU Affero General Public License
|
||||
* (GNU AGPL) as published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version. The code is distributed
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU AGPL for more details.
|
||||
* This file is part of WebODF.
|
||||
*
|
||||
* As additional permission under GNU AGPL version 3 section 7, you
|
||||
* may distribute non-source (e.g., minimized or compacted) forms of
|
||||
* that code without the copy of the GNU GPL normally required by
|
||||
* section 4, provided you include this license notice and a URL
|
||||
* through which recipients can access the Corresponding Source.
|
||||
* WebODF is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Affero General Public License (GNU AGPL)
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* As a special exception to the AGPL, any HTML file which merely makes function
|
||||
* calls to this code, and for that purpose includes it by reference shall be
|
||||
* deemed a separate work for copyright law purposes. In addition, the copyright
|
||||
* holders of this code give you permission to combine this code with free
|
||||
* software libraries that are released under the GNU LGPL. You may copy and
|
||||
* distribute such a system following the terms of the GNU AGPL for this code
|
||||
* and the LGPL for the libraries. If you modify this code, you may extend this
|
||||
* exception to your version of the code, but you are not obligated to do so.
|
||||
* If you do not wish to do so, delete this exception statement from your
|
||||
* version.
|
||||
* WebODF is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* This license applies to this entire compilation.
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with WebODF. If not, see <http://www.gnu.org/licenses/>.
|
||||
* @licend
|
||||
*
|
||||
* @source: http://www.webodf.org/
|
||||
* @source: http://gitorious.org/webodf/webodf/
|
||||
* @source: https://github.com/kogmbh/WebODF/
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is a derivative from a part of Mozilla's PDF.js project. The
|
||||
* original license header follows.
|
||||
*/
|
||||
|
||||
/* Copyright 2012 Mozilla Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/*global document, window*/
|
||||
|
||||
function Viewer(viewerPlugin, docurl) {
|
||||
function Viewer(viewerPlugin, parameters) {
|
||||
"use strict";
|
||||
|
||||
var self = this,
|
||||
|
@ -45,25 +54,88 @@ function Viewer(viewerPlugin, docurl) {
|
|||
kDefaultScaleDelta = 1.1,
|
||||
kDefaultScale = 'auto',
|
||||
presentationMode = false,
|
||||
isFullScreen = false,
|
||||
initialized = false,
|
||||
isSlideshow = false,
|
||||
url,
|
||||
viewerElement,
|
||||
viewerElement = document.getElementById('viewer'),
|
||||
canvasContainer = document.getElementById('canvasContainer'),
|
||||
overlayNavigator = document.getElementById('overlayNavigator'),
|
||||
titlebar = document.getElementById('titlebar'),
|
||||
toolbar = document.getElementById('toolbarContainer'),
|
||||
pageSwitcher = document.getElementById('toolbarLeft'),
|
||||
zoomWidget = document.getElementById('toolbarMiddleContainer'),
|
||||
scaleSelector = document.getElementById('scaleSelect'),
|
||||
filename,
|
||||
dialogOverlay = document.getElementById('dialogOverlay'),
|
||||
toolbarRight = document.getElementById('toolbarRight'),
|
||||
aboutDialog,
|
||||
pages = [],
|
||||
currentPage,
|
||||
scaleChangeTimer,
|
||||
touchTimer;
|
||||
touchTimer,
|
||||
toolbarTouchTimer,
|
||||
/**@const*/
|
||||
UI_FADE_DURATION = 5000;
|
||||
|
||||
function isFullScreen() {
|
||||
// Note that the browser fullscreen (triggered by short keys) might
|
||||
// be considered different from content fullscreen when expecting a boolean
|
||||
return document.isFullScreen || document.mozFullScreen || document.webkitIsFullScreen;
|
||||
function isBlankedOut() {
|
||||
return (blanked.style.display === 'block');
|
||||
}
|
||||
|
||||
function initializeAboutInformation() {
|
||||
var aboutDialogCentererTable, aboutDialogCentererCell, aboutButton, pluginName, pluginVersion, pluginURL;
|
||||
|
||||
if (viewerPlugin) {
|
||||
pluginName = viewerPlugin.getPluginName();
|
||||
pluginVersion = viewerPlugin.getPluginVersion();
|
||||
pluginURL = viewerPlugin.getPluginURL();
|
||||
}
|
||||
|
||||
// Create dialog
|
||||
aboutDialogCentererTable = document.createElement('div');
|
||||
aboutDialogCentererTable.id = "aboutDialogCentererTable";
|
||||
aboutDialogCentererCell = document.createElement('div');
|
||||
aboutDialogCentererCell.id = "aboutDialogCentererCell";
|
||||
aboutDialog = document.createElement('div');
|
||||
aboutDialog.id = "aboutDialog";
|
||||
aboutDialog.innerHTML =
|
||||
"<h1>ViewerJS</h1>" +
|
||||
"<p>Open Source document viewer for webpages, built with HTML and JavaScript.</p>" +
|
||||
"<p>Learn more and get your own copy on the <a href=\"http://viewerjs.org/\" target=\"_blank\">ViewerJS website</a>.</p>" +
|
||||
(viewerPlugin ? ("<p>Using the <a href = \""+ pluginURL + "\" target=\"_blank\">" + pluginName + "</a> " +
|
||||
"(<span id = \"pluginVersion\">" + pluginVersion + "</span>) " +
|
||||
"plugin to show you this document.</p>")
|
||||
: "") +
|
||||
"<p>Supported by <a href=\"http://nlnet.nl\" target=\"_blank\"><br><img src=\"images\/nlnet.png\" width=\"160\" height=\"60\" alt=\"NLnet Foundation\"></a></p>" +
|
||||
"<p>Made by <a href=\"http://kogmbh.com\" target=\"_blank\"><br><img src=\"images\/kogmbh.png\" width=\"172\" height=\"40\" alt=\"KO GmbH\"></a></p>" +
|
||||
"<button id = \"aboutDialogCloseButton\" class = \"toolbarButton textButton\">Close</button>";
|
||||
dialogOverlay.appendChild(aboutDialogCentererTable);
|
||||
aboutDialogCentererTable.appendChild(aboutDialogCentererCell);
|
||||
aboutDialogCentererCell.appendChild(aboutDialog);
|
||||
|
||||
// Create button to open dialog that says "ViewerJS"
|
||||
aboutButton = document.createElement('button');
|
||||
aboutButton.id = "about";
|
||||
aboutButton.className = "toolbarButton textButton about";
|
||||
aboutButton.title = "About";
|
||||
aboutButton.innerHTML = "ViewerJS"
|
||||
toolbarRight.appendChild(aboutButton);
|
||||
|
||||
// Attach events to the above
|
||||
aboutButton.addEventListener('click', function () {
|
||||
showAboutDialog();
|
||||
});
|
||||
document.getElementById('aboutDialogCloseButton').addEventListener('click', function () {
|
||||
hideAboutDialog();
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
function showAboutDialog() {
|
||||
dialogOverlay.style.display = "block";
|
||||
}
|
||||
|
||||
function hideAboutDialog() {
|
||||
dialogOverlay.style.display = "none";
|
||||
}
|
||||
|
||||
function selectScaleOption(value) {
|
||||
|
@ -171,18 +243,38 @@ function Viewer(viewerPlugin, docurl) {
|
|||
delayedRefresh(300);
|
||||
}
|
||||
|
||||
function readZoomParameter(zoom) {
|
||||
var validZoomStrings = ["auto", "page-actual", "page-width"],
|
||||
number;
|
||||
|
||||
this.initialize = function (url) {
|
||||
viewerElement = document.getElementById('viewer');
|
||||
filename = url.replace(/^.*[\\\/]/, '');
|
||||
document.title = filename;
|
||||
document.getElementById('documentName').innerHTML = document.title;
|
||||
if (validZoomStrings.indexOf(zoom) !== -1) {
|
||||
return zoom;
|
||||
}
|
||||
number = parseFloat(zoom);
|
||||
if (number && kMinScale <= number && number <= kMaxScale) {
|
||||
return zoom;
|
||||
}
|
||||
return kDefaultScale;
|
||||
}
|
||||
|
||||
this.initialize = function () {
|
||||
var initialScale,
|
||||
element;
|
||||
|
||||
initialScale = readZoomParameter(parameters.zoom);
|
||||
|
||||
url = parameters.documentUrl;
|
||||
document.title = parameters.filename;
|
||||
var documentName = document.getElementById('documentName');
|
||||
documentName.innerHTML = "";
|
||||
documentName.appendChild(documentName.ownerDocument.createTextNode(parameters.filename));
|
||||
|
||||
viewerPlugin.onLoad = function () {
|
||||
// document.getElementById('pluginVersion').innerHTML = viewerPlugin.getPluginVersion();
|
||||
isSlideshow = viewerPlugin.isSlideshow();
|
||||
if (isSlideshow) {
|
||||
// No padding for slideshows
|
||||
canvasContainer.style.padding = 0;
|
||||
// Slideshow pages should be centered
|
||||
canvasContainer.classList.add("slideshow");
|
||||
// Show page nav controls only for presentations
|
||||
pageSwitcher.style.visibility = 'visible';
|
||||
} else {
|
||||
|
@ -201,7 +293,7 @@ function Viewer(viewerPlugin, docurl) {
|
|||
self.showPage(1);
|
||||
|
||||
// Set default scale
|
||||
parseScale(kDefaultScale);
|
||||
parseScale(initialScale);
|
||||
|
||||
canvasContainer.onscroll = onScroll;
|
||||
delayedRefresh();
|
||||
|
@ -260,21 +352,31 @@ function Viewer(viewerPlugin, docurl) {
|
|||
*/
|
||||
this.toggleFullScreen = function () {
|
||||
var elem = viewerElement;
|
||||
if (!isFullScreen()) {
|
||||
if (elem.requestFullScreen) {
|
||||
elem.requestFullScreen();
|
||||
if (!isFullScreen) {
|
||||
if (elem.requestFullscreen) {
|
||||
elem.requestFullscreen();
|
||||
} else if (elem.mozRequestFullScreen) {
|
||||
elem.mozRequestFullScreen();
|
||||
} else if (elem.webkitRequestFullscreen) {
|
||||
elem.webkitRequestFullscreen();
|
||||
} else if (elem.webkitRequestFullScreen) {
|
||||
elem.webkitRequestFullScreen();
|
||||
elem.webkitRequestFullScreen(Element.ALLOW_KEYBOARD_INPUT);
|
||||
} else if (elem.msRequestFullscreen) {
|
||||
elem.msRequestFullscreen();
|
||||
}
|
||||
} else {
|
||||
if (document.cancelFullScreen) {
|
||||
if (document.exitFullscreen) {
|
||||
document.exitFullscreen();
|
||||
} else if (document.cancelFullScreen) {
|
||||
document.cancelFullScreen();
|
||||
} else if (document.mozCancelFullScreen) {
|
||||
document.mozCancelFullScreen();
|
||||
} else if (document.webkitExitFullscreen) {
|
||||
document.webkitExitFullscreen();
|
||||
} else if (document.webkitCancelFullScreen) {
|
||||
document.webkitCancelFullScreen();
|
||||
} else if (document.msExitFullscreen) {
|
||||
document.msExitFullscreen();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -284,14 +386,12 @@ function Viewer(viewerPlugin, docurl) {
|
|||
* Presentation mode involves fullscreen + hidden UI controls
|
||||
*/
|
||||
this.togglePresentationMode = function () {
|
||||
var titlebar = document.getElementById('titlebar'),
|
||||
toolbar = document.getElementById('toolbarContainer'),
|
||||
overlayCloseButton = document.getElementById('overlayCloseButton');
|
||||
var overlayCloseButton = document.getElementById('overlayCloseButton');
|
||||
|
||||
if (!presentationMode) {
|
||||
titlebar.style.display = toolbar.style.display = 'none';
|
||||
overlayCloseButton.style.display = 'block';
|
||||
canvasContainer.className = 'presentationMode';
|
||||
canvasContainer.classList.add('presentationMode');
|
||||
isSlideshow = true;
|
||||
canvasContainer.onmousedown = function (event) {
|
||||
event.preventDefault();
|
||||
|
@ -309,9 +409,12 @@ function Viewer(viewerPlugin, docurl) {
|
|||
};
|
||||
parseScale('page-fit');
|
||||
} else {
|
||||
if (isBlankedOut()) {
|
||||
leaveBlankOut();
|
||||
}
|
||||
titlebar.style.display = toolbar.style.display = 'block';
|
||||
overlayCloseButton.style.display = 'none';
|
||||
canvasContainer.className = '';
|
||||
canvasContainer.classList.remove('presentationMode');
|
||||
canvasContainer.onmouseup = function () {};
|
||||
canvasContainer.oncontextmenu = function () {};
|
||||
canvasContainer.onmousedown = function () {};
|
||||
|
@ -362,123 +465,213 @@ function Viewer(viewerPlugin, docurl) {
|
|||
};
|
||||
|
||||
function cancelPresentationMode() {
|
||||
if (presentationMode && !isFullScreen()) {
|
||||
if (presentationMode && !isFullScreen) {
|
||||
self.togglePresentationMode();
|
||||
}
|
||||
}
|
||||
|
||||
function handleFullScreenChange() {
|
||||
isFullScreen = !isFullScreen;
|
||||
cancelPresentationMode();
|
||||
}
|
||||
|
||||
function showOverlayNavigator() {
|
||||
if (isSlideshow) {
|
||||
overlayNavigator.className = 'touched';
|
||||
overlayNavigator.className = 'viewer-touched';
|
||||
window.clearTimeout(touchTimer);
|
||||
touchTimer = window.setTimeout(function () {
|
||||
overlayNavigator.className = '';
|
||||
}, 2000);
|
||||
}, UI_FADE_DURATION);
|
||||
}
|
||||
}
|
||||
|
||||
function init(docurl) {
|
||||
/**
|
||||
* @param {!boolean} timed Fade after a while
|
||||
*/
|
||||
function showToolbars() {
|
||||
titlebar.classList.add('viewer-touched');
|
||||
toolbar.classList.add('viewer-touched');
|
||||
window.clearTimeout(toolbarTouchTimer);
|
||||
toolbarTouchTimer = window.setTimeout(function () {
|
||||
hideToolbars();
|
||||
}, UI_FADE_DURATION);
|
||||
}
|
||||
|
||||
self.initialize(docurl);
|
||||
function hideToolbars() {
|
||||
titlebar.classList.remove('viewer-touched');
|
||||
toolbar.classList.remove('viewer-touched');
|
||||
}
|
||||
|
||||
if (!(document.cancelFullScreen || document.mozCancelFullScreen || document.webkitCancelFullScreen)) {
|
||||
document.getElementById('fullscreen').style.visibility = 'hidden';
|
||||
function toggleToolbars() {
|
||||
if (titlebar.classList.contains('viewer-touched')) {
|
||||
hideToolbars();
|
||||
} else {
|
||||
showToolbars();
|
||||
}
|
||||
}
|
||||
|
||||
document.getElementById('overlayCloseButton').addEventListener('click', self.toggleFullScreen);
|
||||
document.getElementById('fullscreen').addEventListener('click', self.toggleFullScreen);
|
||||
document.getElementById('presentation').addEventListener('click', function () {
|
||||
if (!isFullScreen()) {
|
||||
self.toggleFullScreen();
|
||||
function blankOut(value) {
|
||||
blanked.style.display = 'block';
|
||||
blanked.style.backgroundColor = value;
|
||||
hideToolbars();
|
||||
}
|
||||
|
||||
function leaveBlankOut() {
|
||||
blanked.style.display = 'none';
|
||||
toggleToolbars();
|
||||
}
|
||||
|
||||
function init() {
|
||||
|
||||
// initializeAboutInformation();
|
||||
if (viewerPlugin) {
|
||||
|
||||
self.initialize();
|
||||
|
||||
if (!(document.exitFullscreen || document.cancelFullScreen || document.mozCancelFullScreen || document.webkitExitFullscreen || document.webkitCancelFullScreen || document.msExitFullscreen)) {
|
||||
document.getElementById('fullscreen').style.visibility = 'hidden';
|
||||
document.getElementById('presentation').style.visibility = 'hidden';
|
||||
}
|
||||
self.togglePresentationMode();
|
||||
});
|
||||
|
||||
document.addEventListener('fullscreenchange', cancelPresentationMode);
|
||||
document.addEventListener('webkitfullscreenchange', cancelPresentationMode);
|
||||
document.addEventListener('mozfullscreenchange', cancelPresentationMode);
|
||||
document.getElementById('overlayCloseButton').addEventListener('click', self.toggleFullScreen);
|
||||
document.getElementById('fullscreen').addEventListener('click', self.toggleFullScreen);
|
||||
document.getElementById('presentation').addEventListener('click', function () {
|
||||
if (!isFullScreen) {
|
||||
self.toggleFullScreen();
|
||||
}
|
||||
self.togglePresentationMode();
|
||||
});
|
||||
|
||||
document.getElementById('download').addEventListener('click', function () {
|
||||
self.download();
|
||||
});
|
||||
document.addEventListener('fullscreenchange', handleFullScreenChange);
|
||||
document.addEventListener('webkitfullscreenchange', handleFullScreenChange);
|
||||
document.addEventListener('mozfullscreenchange', handleFullScreenChange);
|
||||
document.addEventListener('MSFullscreenChange', handleFullScreenChange);
|
||||
|
||||
document.getElementById('zoomOut').addEventListener('click', function () {
|
||||
self.zoomOut();
|
||||
});
|
||||
document.getElementById('download').addEventListener('click', function () {
|
||||
self.download();
|
||||
});
|
||||
|
||||
document.getElementById('zoomIn').addEventListener('click', function () {
|
||||
self.zoomIn();
|
||||
});
|
||||
document.getElementById('zoomOut').addEventListener('click', function () {
|
||||
self.zoomOut();
|
||||
});
|
||||
|
||||
document.getElementById('previous').addEventListener('click', function () {
|
||||
self.showPreviousPage();
|
||||
});
|
||||
document.getElementById('zoomIn').addEventListener('click', function () {
|
||||
self.zoomIn();
|
||||
});
|
||||
|
||||
document.getElementById('next').addEventListener('click', function () {
|
||||
self.showNextPage();
|
||||
});
|
||||
|
||||
document.getElementById('previousPage').addEventListener('click', function () {
|
||||
self.showPreviousPage();
|
||||
});
|
||||
|
||||
document.getElementById('nextPage').addEventListener('click', function () {
|
||||
self.showNextPage();
|
||||
});
|
||||
|
||||
document.getElementById('pageNumber').addEventListener('change', function () {
|
||||
self.showPage(this.value);
|
||||
});
|
||||
|
||||
document.getElementById('scaleSelect').addEventListener('change', function () {
|
||||
parseScale(this.value);
|
||||
});
|
||||
|
||||
canvasContainer.addEventListener('click', showOverlayNavigator);
|
||||
overlayNavigator.addEventListener('click', showOverlayNavigator);
|
||||
|
||||
window.addEventListener('scalechange', function (evt) {
|
||||
var customScaleOption = document.getElementById('customScaleOption'),
|
||||
predefinedValueFound = selectScaleOption(String(evt.scale));
|
||||
|
||||
customScaleOption.selected = false;
|
||||
|
||||
if (!predefinedValueFound) {
|
||||
customScaleOption.textContent = Math.round(evt.scale * 10000) / 100 + '%';
|
||||
customScaleOption.selected = true;
|
||||
}
|
||||
}, true);
|
||||
|
||||
window.addEventListener('resize', function (evt) {
|
||||
if (initialized &&
|
||||
(document.getElementById('pageWidthOption').selected ||
|
||||
document.getElementById('pageAutoOption').selected)) {
|
||||
parseScale(document.getElementById('scaleSelect').value);
|
||||
}
|
||||
showOverlayNavigator();
|
||||
});
|
||||
|
||||
window.addEventListener('keydown', function (evt) {
|
||||
var key = evt.keyCode,
|
||||
shiftKey = evt.shiftKey;
|
||||
|
||||
switch (key) {
|
||||
case 33: // pageUp
|
||||
case 38: // up
|
||||
case 37: // left
|
||||
document.getElementById('previous').addEventListener('click', function () {
|
||||
self.showPreviousPage();
|
||||
break;
|
||||
case 34: // pageDown
|
||||
case 40: // down
|
||||
case 39: // right
|
||||
});
|
||||
|
||||
document.getElementById('next').addEventListener('click', function () {
|
||||
self.showNextPage();
|
||||
break;
|
||||
case 32: // space
|
||||
shiftKey ? self.showPreviousPage() : self.showNextPage();
|
||||
break;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
document.getElementById('previousPage').addEventListener('click', function () {
|
||||
self.showPreviousPage();
|
||||
});
|
||||
|
||||
document.getElementById('nextPage').addEventListener('click', function () {
|
||||
self.showNextPage();
|
||||
});
|
||||
|
||||
document.getElementById('pageNumber').addEventListener('change', function () {
|
||||
self.showPage(this.value);
|
||||
});
|
||||
|
||||
document.getElementById('scaleSelect').addEventListener('change', function () {
|
||||
parseScale(this.value);
|
||||
});
|
||||
|
||||
canvasContainer.addEventListener('click', showOverlayNavigator);
|
||||
overlayNavigator.addEventListener('click', showOverlayNavigator);
|
||||
canvasContainer.addEventListener('click', toggleToolbars);
|
||||
titlebar.addEventListener('click', showToolbars);
|
||||
toolbar.addEventListener('click', showToolbars);
|
||||
|
||||
window.addEventListener('scalechange', function (evt) {
|
||||
var customScaleOption = document.getElementById('customScaleOption'),
|
||||
predefinedValueFound = selectScaleOption(String(evt.scale));
|
||||
|
||||
customScaleOption.selected = false;
|
||||
|
||||
if (!predefinedValueFound) {
|
||||
customScaleOption.textContent = Math.round(evt.scale * 10000) / 100 + '%';
|
||||
customScaleOption.selected = true;
|
||||
}
|
||||
}, true);
|
||||
|
||||
window.addEventListener('resize', function (evt) {
|
||||
if (initialized &&
|
||||
(document.getElementById('pageWidthOption').selected ||
|
||||
document.getElementById('pageAutoOption').selected)) {
|
||||
parseScale(document.getElementById('scaleSelect').value);
|
||||
}
|
||||
showOverlayNavigator();
|
||||
});
|
||||
|
||||
window.addEventListener('keydown', function (evt) {
|
||||
var key = evt.keyCode,
|
||||
shiftKey = evt.shiftKey;
|
||||
|
||||
// blanked-out mode?
|
||||
if (isBlankedOut()) {
|
||||
switch (key) {
|
||||
case 16: // Shift
|
||||
case 17: // Ctrl
|
||||
case 18: // Alt
|
||||
case 91: // LeftMeta
|
||||
case 93: // RightMeta
|
||||
case 224: // MetaInMozilla
|
||||
case 225: // AltGr
|
||||
// ignore modifier keys alone
|
||||
break;
|
||||
default:
|
||||
leaveBlankOut();
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
switch (key) {
|
||||
case 8: // backspace
|
||||
case 33: // pageUp
|
||||
case 37: // left arrow
|
||||
case 38: // up arrow
|
||||
case 80: // key 'p'
|
||||
self.showPreviousPage();
|
||||
break;
|
||||
case 13: // enter
|
||||
case 34: // pageDown
|
||||
case 39: // right arrow
|
||||
case 40: // down arrow
|
||||
case 78: // key 'n'
|
||||
self.showNextPage();
|
||||
break;
|
||||
case 32: // space
|
||||
shiftKey ? self.showPreviousPage() : self.showNextPage();
|
||||
break;
|
||||
case 66: // key 'b' blanks screen (to black) or returns to the document
|
||||
case 190: // and so does the key '.' (dot)
|
||||
if (presentationMode) {
|
||||
blankOut('#000');
|
||||
}
|
||||
break;
|
||||
case 87: // key 'w' blanks page (to white) or returns to the document
|
||||
case 188: // and so does the key ',' (comma)
|
||||
if (presentationMode) {
|
||||
blankOut('#FFF');
|
||||
}
|
||||
break;
|
||||
case 36: // key 'Home' goes to first page
|
||||
self.showPage(0);
|
||||
break;
|
||||
case 35: // key 'End' goes to last page
|
||||
self.showPage(pages.length);
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
init(docurl);
|
||||
init();
|
||||
}
|
||||
|
|
File diff suppressed because one or more lines are too long
Loading…
Add table
Reference in a new issue