Commit 97dc979f authored by onny's avatar onny

Initial commit

parents
Pipeline #28 canceled with stages
app_name=files_pdfviewer
project_dir=$(CURDIR)/../$(app_name)
build_dir=$(CURDIR)/build/artifacts
appstore_dir=$(build_dir)/appstore
source_dir=$(build_dir)/source
sign_dir=$(build_dir)/sign
package_name=$(app_name)
cert_dir=$(HOME)/.nextcloud/certificates
version+=1.3.2
all: appstore
release: appstore create-tag
create-tag:
git tag -s -a v$(version) -m "Tagging the $(version) release."
git push origin v$(version)
clean:
rm -rf $(build_dir)
rm -rf node_modules
appstore: clean
mkdir -p $(sign_dir)
rsync -a \
--exclude=/build \
--exclude=/docs \
--exclude=/translationfiles \
--exclude=/.tx \
--exclude=/tests \
--exclude=/screenshots \
--exclude=/.git \
--exclude=/.github \
--exclude=/l10n/l10n.pl \
--exclude=/CONTRIBUTING.md \
--exclude=/issue_template.md \
--exclude=/README.md \
--exclude=/.gitattributes \
--exclude=/.gitignore \
--exclude=/.scrutinizer.yml \
--exclude=/.travis.yml \
--exclude=/Makefile \
--exclude=/.drone.yml \
$(project_dir)/ $(sign_dir)/$(app_name)
@if [[ -f $(cert_dir)/$(app_name).key && -f $(cert_dir)/$(app_name).crt ]]; then \
../../occ integrity:sign-app --path $(sign_dir)/$(app_name) \
--privateKey $(cert_dir)/$(app_name).key \
--certificate $(cert_dir)/$(app_name).crt; \
fi
tar -czf $(build_dir)/$(app_name)-$(version).tar.gz \
-C $(sign_dir) $(app_name)
@if [ -f $(cert_dir)/$(app_name).key ]; then \
echo "Signing package…"; \
openssl dgst -sha512 -sign $(cert_dir)/$(app_name).key $(build_dir)/$(app_name)-$(version).tar.gz | openssl base64; \
fi
files_pdfviewer
======
This application integrates the [PDF.js](https://mozilla.github.io/pdf.js/) library into Nextcloud. Using this application users can view their PDF files online without downloading the file.
[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/owncloud/files_pdfviewer/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/nextcloud/files_pdfviewer/?branch=master)
[![Code Coverage](https://scrutinizer-ci.com/g/owncloud/files_pdfviewer/badges/coverage.png?b=master)](https://scrutinizer-ci.com/g/nextcloud/files_pdfviewer/?branch=master)
[![Build Status](https://travis-ci.org/owncloud/files_pdfviewer.svg)](https://travis-ci.org/nextcloud/files_pdfviewer)
Maintainers
===========
- [Lukas Reschke](https://github.com/LukasReschke)
<?php
declare(strict_types=1);
/**
* @author Lukas Reschke
* @copyright 2014 Lukas Reschke lukas@owncloud.com
*
* This file is licensed under the Affero General Public License version 3 or
* later.
* See the COPYING-README file.
*/
namespace OCA\Files_PdfViewer\AppInfo;
use OCP\Util;
Util::addScript('files_pdfviewer', 'previewplugin');
Util::addStyle('files_pdfviewer', 'style');
<?xml version="1.0"?>
<info>
<id>files_ebookreader</id>
<name>Ebook reader</name>
<summary>An ebook reader for Nextcloud</summary>
<description><![CDATA[This application integrates the PDF.js library into Nextcloud. Using this
application users can view their PDF files online without the need to
download the file.
When this application is enabled publicly shared PDF documents will also
get shown in the PDF viewer instead of only showing a single static
snapshot of the document. The PDF viewer requires a modern browser and
will not work with Microsoft® Internet Explorer® versions below 9.
PDF.js is a JavaScript library developed by Mozilla, you can learn more
about the PDF.js project at [https://mozilla.github.io/pdf.js/](https://mozilla.github.io/pdf.js/)]]></description>
<version>0.1</version>
<licence>mit</licence>
<author>Jonas Heinrich</author>
<namespace>Files_PdfViewer</namespace>
<default_enable/>
<category>files</category>
<category>office</category>
<bugs>https://github.com/nextcloud/files_pdfviewer/issues</bugs>
<dependencies>
<nextcloud min-version="15" max-version="15" />
</dependencies>
</info>
<?php
declare(strict_types=1);
/**
* @author Lukas Reschke
* @copyright 2014 Lukas Reschke lukas@owncloud.com
*
* This file is licensed under the Affero General Public License version 3 or
* later.
* See the COPYING-README file.
*/
namespace OCA\Files_PdfViewer\AppInfo;
return ['routes' => [
['name' => 'display#showPdfViewer', 'url' => '/', 'verb' => 'GET'],
]];
.toolbar {
display: none;
}
#viewerContainer {
top: 0 !important;
}
body {
background-color: #fff;
background-image: none;
}
.pdfViewer .page {
margin: 10px auto;
border: 1px solid #ddd;
border-image: none;
}
/* Force hide the sidebar in the thumbnail, as whether it is shown or not
* depends on whether it was open or not the last time that the main viewer was
* used. */
#sidebarContainer {
display: none;
}
/* force full height on public template */
#body-public .full-height {
height: 100%;
}
#body-public footer.hidden {
display: none;
}
#pdframe {
/* The PDF frame uses an absolute position and thus fills the whole padding
* box of the content, so the top padding is needed here too to not overlap
* the header. */
padding-top: inherit;
}
.toolbarButton#secondaryToolbarClose::before {
display: block;
content: ' ';
background-image: url(../img/toolbarButton-secondaryToolbarClose.svg);
background-size: 16px 16px;
height: 16px;
width: 16px;
}
@media screen and (min-resolution: 2dppx) {
#secondaryToolbarClose::before {
background-size: 32px 32px !important;
height: 32px !important;
width: 32px !important;
}
}
html .doorHangerRight:after {
right: 53px!important;
}
html .doorHangerRight:before {
right: 53px!important;
}
img/app.png

638 Bytes

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg xmlns="http://www.w3.org/2000/svg" height="32" width="32" version="1.0" viewBox="0 0 32 32">
<path style="color:#000000;block-progression:tb;text-transform:none;text-indent:0" d="m4.6992 2.002v0.0019c-0.395 0.0764-0.7062 0.4666-0.6992 0.875v26.244c0 0.458 0.4122 0.875 0.8633 0.875h22.278c0.451 0 0.863-0.417 0.863-0.875v-20.285c-0.008-0.1338-0.045-0.2659-0.109-0.3829l-6.625-6.3985c-0.086-0.0328-0.178-0.051-0.27-0.0546h-16.137c-0.0534-0.0052-0.1101-0.0052-0.1638 0zm10.014 3.998h0.385c0.371 0 0.728 0.1326 0.986 0.3906 1.065 1.0644 0.564 3.6574 0.031 5.8024-0.032 0.097-0.046 0.181-0.062 0.229 0.645 1.822 1.564 3.288 2.58 4.127 0.419 0.322 0.886 0.645 1.402 0.935 0.726-0.08 1.419-0.113 2.08-0.113 2 0 3.212 0.355 3.68 1.113 0.161 0.258 0.24 0.563 0.191 0.885-0.016 0.403-0.161 0.776-0.451 1.067-0.274 0.306-0.757 0.482-1.467 0.482-1.225 0-3.228-0.371-4.841-1.193-2.775 0.306-4.837 0.678-6.498 1.211-0.081 0.032-0.179 0.063-0.291 0.111-2 3.42-3.4832 4.953-4.7896 4.953-0.2582 0-0.5173-0.064-0.7109-0.178l-0.7734-0.498-0.0489-0.082c-0.113-0.29-0.1464-0.567-0.082-0.873 0.1774-0.854 1.0976-2.21 3.0332-3.42 0.3064-0.226 0.7904-0.483 1.4356-0.789 0.484-0.838 1-1.822 1.549-2.902 0.822-1.661 1.337-3.304 1.74-4.723v-0.017c-0.597-1.952-0.952-3.1289-0.355-5.2739 0.145-0.6128 0.68-1.2441 1.277-1.2441zm0.24 1c-0.032 0.0484-0.081 0.1289-0.113 0.1934-0.274 0.6773-0.258 1.8551 0.113 3.3066l0.082-0.062c0.113-0.5166 0.161-0.968 0.258-1.3228l0.047-0.2597c0.161-0.9192 0.128-1.3884-0.147-1.7754l-0.24-0.0801zm0.131 7.293c-0.371 1.193-0.905 2.467-1.631 3.869-0.322 0.613-0.678 1.192-0.807 1.676l0.176-0.065c2.049-0.79 3.988-1.24 5.391-1.498-0.242-0.161-0.469-0.34-0.662-0.517-0.968-0.823-1.806-2.014-2.467-3.465zm6.723 4.432c-0.113 0-0.222 0.002-0.368 0.164 1.178 0.516 2.319 0.822 3.061 0.822 0.113 0 0.212-0.017 0.309-0.033h0.064c0.081-0.033 0.128-0.052 0.145-0.213-0.033-0.049-0.064-0.111-0.145-0.176-0.161-0.161-0.808-0.564-3.066-0.564zm-11.723 2.92c-0.3387 0.193-0.6161 0.371-0.7774 0.5-1.1452 1.048-1.8685 2.111-1.9492 2.724 0.7258-0.242 1.6782-1.305 2.7266-3.224z" fill="#fff"/>
</svg>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg xmlns="http://www.w3.org/2000/svg" height="32" width="32" version="1.1">
<path d="m23.071 6.1013 2.8278 2.8278-7.0713 7.0717 7.071 7.0704-2.8279 2.8283-7.0714-7.0704l-7.0713 7.071-2.8282-2.828 7.0705-7.071-7.1084-7.0316 2.8665-2.8679 7.0709 7.0705z" fill="#FFF"/>
</svg>
/*
* Copyright (c) 2013-2014 Lukas Reschke <lukas@owncloud.com>
*
* This file is licensed under the Affero General Public License version 3
* or later.
*
* See the COPYING-README file.
*
*/
(function(OCA) {
OCA.FilesPdfViewer = OCA.FilesPdfViewer || {};
/**
* @namespace OCA.FilesPdfViewer.PreviewPlugin
*/
OCA.FilesPdfViewer.PreviewPlugin = {
/**
* @param fileList
*/
attach: function(fileList) {
this._extendFileActions(fileList.fileActions);
},
hide: function() {
$('#pdframe').remove();
if ($('#isPublic').val() && $('#filesApp').val()){
$('#controls').removeClass('hidden');
$('#content').removeClass('full-height');
$('footer').removeClass('hidden');
}
if (typeof FileList !== 'undefined') {
FileList.setViewerMode(false);
}
// replace the controls with our own
$('#app-content #controls').removeClass('hidden');
},
/**
* @param downloadUrl
* @param isFileList
*/
show: function(downloadUrl, isFileList) {
var self = this;
var shown = true;
var $iframe;
var viewer = OC.generateUrl('/apps/files_pdfviewer/?file={file}', {file: downloadUrl});
$iframe = $('<iframe id="pdframe" style="width:100%;height:100%;display:block;position:absolute;top:0;z-index:1041;left:0;" src="'+viewer+'" sandbox="allow-scripts allow-same-origin allow-popups allow-modals allow-top-navigation" allowfullscreen="true"/>');
if(isFileList === true) {
FileList.setViewerMode(true);
}
if ($('#isPublic').val()) {
// force the preview to adjust its height
$('#preview').append($iframe).css({height: '100%'});
$('body').css({height: '100%'});
$('#content').addClass('full-height');
$('footer').addClass('hidden');
$('#imgframe').addClass('hidden');
$('.directLink').addClass('hidden');
$('.directDownload').addClass('hidden');
$('#controls').addClass('hidden');
} else {
$('#app-content').after($iframe);
}
$("#pageWidthOption").attr("selected","selected");
// replace the controls with our own
$('#app-content #controls').addClass('hidden');
// if a filelist is present, the PDF viewer can be closed to go back there
$('#pdframe').load(function(){
var iframe = $('#pdframe').contents();
if ($('#fileList').length)
{
iframe.find('#secondaryToolbarClose').click(function() {
self.hide();
});
// Go back on ESC
$(document).keyup(function(e) {
if (shown && e.keyCode == 27) {
shown = false;
self.hide();
}
});
} else {
iframe.find("#secondaryToolbarClose").addClass('hidden');
}
});
if(!$('html').hasClass('ie8')) {
history.pushState({}, '', '#pdfviewer');
}
if(!$('html').hasClass('ie8')) {
$(window).one('popstate', function (e) {
self.hide();
});
}
},
/**
* @param fileActions
* @private
*/
_extendFileActions: function(fileActions) {
var self = this;
fileActions.registerAction({
name: 'view',
displayName: 'Favorite',
mime: 'application/epub+zip',
permissions: OC.PERMISSION_READ,
actionHandler: function(fileName, context) {
var downloadUrl = context.fileList.getDownloadUrl(fileName, context.dir);
if (downloadUrl && downloadUrl !== '#') {
self.show(downloadUrl, true);
}
}
});
fileActions.setDefault('application/epub+zip', 'view');
}
};
})(OCA);
OC.Plugins.register('OCA.Files.FileList', OCA.FilesPdfViewer.PreviewPlugin);
// FIXME: Hack for single public file view since it is not attached to the fileslist
$(document).ready(function(){
if ($('#isPublic').val() && $('#mimetype').val() === 'application/epub+zip') {
var sharingToken = $('#sharingToken').val();
var downloadUrl = OC.generateUrl('/s/{token}/download', {token: sharingToken});
var viewer = OCA.FilesPdfViewer.PreviewPlugin;
viewer.show(downloadUrl, false);
}
});
(function () {
var SidebarPreview = function () { };
SidebarPreview.prototype = {
attach: function (manager) {
manager.addPreviewHandler('application/epub+zip', this.handlePreview.bind(this));
},
handlePreview: function (model, $thumbnailDiv, $thumbnailContainer, fallback) {
var previewWidth = Math.floor($thumbnailContainer.parent().width() + 50); // 50px for negative margins
var previewHeight = Math.floor(previewWidth / (16 / 9));
var downloadUrl = Files.getDownloadUrl(model.get('name'), model.get('path'));
var viewer = OC.generateUrl('/apps/files_pdfviewer/?minmode=true&file={file}', {file: downloadUrl});
var $iframe = $('<iframe id="pdframe-sidebar" style="width:100%;height:' + previewHeight + 'px;display:block;" src="' + viewer + '" sandbox="allow-scripts allow-same-origin allow-popups allow-modals" />');
$thumbnailDiv.append($iframe);
$iframe.on('load', function() {
$thumbnailDiv.removeClass('icon-loading icon-32');
$thumbnailContainer.addClass('large');
$thumbnailDiv.children('.stretcher').remove();
$thumbnailContainer.css("max-height", previewHeight);
});
},
getFileContent: function (path) {
return $.get(OC.linkToRemoteBase('files' + path));
}
};
OC.Plugins.register('OCA.Files.SidebarPreviewManager', new SidebarPreview());
})();
/**
* Checks if the page is displayed in an iframe. If not redirect to /.
**/
function redirectIfNotDisplayedInFrame () {
try {
if (window.frameElement) {
return;
}
} catch (e) {}
window.location.href = '/';
}
redirectIfNotDisplayedInFrame();
// When "PDFViewerApplication.initialize" is executed it overwrites the value of
// "PDFJS.workerSrc", so the custom initialization has to be executed after
// that. As "PDFViewerApplication" does not provide any hookable point for
// custom initialization in its initialization routine a dirty hack has to be
// used.
//
// When "vendor/pdfjs/web/viewer.js" is parsed at the end it calls
// "PDFViewerApplication.initialize" (either directly or as a "DOMContentLoaded"
// event handler), and "PDFViewerApplication.initialize" sends an asynchronous
// XHR request to initialize the locales, which causes the execution flow to
// continue with the next script or the next "DOMContentLoaded" handler. Thanks
// to this "initializeCustomPDFViewerApplication" can be executed at that point
// by parsing "js/workersrc.js" after "vendor/pdfjs/web/viewer.js" and either
// calling it directly or adding it as a "DOMContentLoaded" event handler (using
// the same conditions as in "vendor/pdfjs/web/viewer.js").
function initializeCustomPDFViewerApplication() {
PDFJS.openExternalLinksInNewWindow = true;
PDFJS.isEvalSupported = false;
PDFJS.workerSrc = document.getElementsByTagName('head')[0].getAttribute('data-workersrc');
// The download has to be forced to use the URL of the file; by default
// "PDFViewerApplication.download" uses a blob, but this causes a CSP error
// (at least, in Firefox) when trying to download it.
PDFViewerApplication.download = function() {
// "isDataSchema()" and "getPDFFileNameFromURL()" are copied from
// "vendor/pdfjs/web/viewer.js", as the functions defined in that file
// can not be accessed from the outside.
function isDataSchema(url) {
var i = 0,
ii = url.length;
while (i < ii && url[i].trim() === '') {
i++;
}
return url.substr(i, 5).toLowerCase() === 'data:';
}
function getPDFFileNameFromURL(url) {
var defaultFilename = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'document.pdf';
if (isDataSchema(url)) {
console.warn('getPDFFileNameFromURL: ' + 'ignoring "data:" URL for performance reasons.');
return defaultFilename;
}
var reURI = /^(?:(?:[^:]+:)?\/\/[^\/]+)?([^?#]*)(\?[^#]*)?(#.*)?$/;
var reFilename = /[^\/?#=]+\.pdf\b(?!.*\.pdf\b)/i;
var splitURI = reURI.exec(url);
var suggestedFilename = reFilename.exec(splitURI[1]) || reFilename.exec(splitURI[2]) || reFilename.exec(splitURI[3]);
if (suggestedFilename) {
suggestedFilename = suggestedFilename[0];
if (suggestedFilename.indexOf('%') !== -1) {
try {
suggestedFilename = reFilename.exec(decodeURIComponent(suggestedFilename))[0];
} catch (ex) {}
}
}
return suggestedFilename || defaultFilename;
}
var url = decodeURIComponent(window.location.search.substr(6));
this.downloadManager.downloadUrl(url, getPDFFileNameFromURL(url));
};
}
if (document.readyState === 'interactive' || document.readyState === 'complete') {
initializeCustomPDFViewerApplication();
} else {
document.addEventListener('DOMContentLoaded', initializeCustomPDFViewerApplication, true);
}
<?php
declare(strict_types=1);
/**
* @author Lukas Reschke
* @copyright 2014 Lukas Reschke lukas@owncloud.com
*
* This file is licensed under the Affero General Public License version 3 or
* later.
* See the COPYING-README file.
*/
namespace OCA\Files_PdfViewer\Controller;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http\ContentSecurityPolicy;
use OCP\AppFramework\Http\TemplateResponse;
use OCP\IRequest;
use OCP\IURLGenerator;
class DisplayController extends Controller {
/** @var IURLGenerator */
private $urlGenerator;
/**
* @param string $AppName
* @param IRequest $request
* @param IURLGenerator $urlGenerator
*/
public function __construct(string $AppName,
IRequest $request,
IURLGenerator $urlGenerator) {
parent::__construct($AppName, $request);
$this->urlGenerator = $urlGenerator;
}
/**
* @PublicPage
* @NoCSRFRequired
*
* @param bool $minmode
* @return TemplateResponse
*/
public function showPdfViewer(bool $minmode = false): TemplateResponse {
$params = [
'urlGenerator' => $this->urlGenerator,
'minmode' => $minmode
];
$response = new TemplateResponse($this->appName, 'viewer', $params, 'blank');
$policy = new ContentSecurityPolicy();
$policy->addAllowedChildSrcDomain('\'self\'');
$policy->addAllowedFontDomain('data:');
$policy->addAllowedImageDomain('*');