Rendering PDFs using PDF.js (client portal) (#3589)

* Wip for testing

* Rendering PDFs using pdf.js
This commit is contained in:
Benjamin Beganović 2020-04-03 22:12:12 +02:00 committed by GitHub
parent b162fde79e
commit a87ae37ce1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 229 additions and 8 deletions

2
public/css/app.css vendored

File diff suppressed because one or more lines are too long

2
public/js/clients/shared/pdf.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,9 @@
/**
* Invoice Ninja (https://invoiceninja.com)
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2020. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://opensource.org/licenses/AAL
*/

22
public/js/vendor/pdf.js/pdf.min.js vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,11 +1,12 @@
{
"/js/app.js": "/js/app.js?id=8b49701583f407403ddf",
"/css/app.css": "/css/app.css?id=0cc15fdcb4d64dfeda0e",
"/css/app.css": "/css/app.css?id=422c8d1b7e15aa054cd7",
"/js/clients/invoices/action-selectors.js": "/js/clients/invoices/action-selectors.js?id=caec43815d9a13168a38",
"/js/clients/invoices/payment.js": "/js/clients/invoices/payment.js?id=af49e24958be5fc00c92",
"/js/clients/payment_methods/authorize-stripe-card.js": "/js/clients/payment_methods/authorize-stripe-card.js?id=f4c45f0da9868d840799",
"/js/clients/payments/process.js": "/js/clients/payments/process.js?id=bb91cb611d1bdab40973",
"/js/clients/quotes/action-selectors.js": "/js/clients/quotes/action-selectors.js?id=f7c6bfdbf9cfc3efdf0b",
"/js/clients/quotes/approve.js": "/js/clients/quotes/approve.js?id=fcb23f15eebc3bff639d",
"/js/clients/shared/pdf.js": "/js/clients/shared/pdf.js?id=5e05bbd189e1f70e0c27",
"/js/setup/setup.js": "/js/setup/setup.js?id=d30808ba9e2c9f908ce5"
}

78
resources/js/clients/shared/pdf.js vendored Normal file
View File

@ -0,0 +1,78 @@
/**
* Invoice Ninja (https://invoiceninja.com)
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2020. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://opensource.org/licenses/AAL
*/
class PDF {
constructor(url, canvas) {
this.url = url;
this.canvas = canvas;
this.context = canvas.getContext("2d");
this.currentPage = 1;
this.maxPages = 1;
}
handlePreviousPage() {
if (this.currentPage == 1) {
return;
}
this.currentPage -= 1;
this.handle();
}
handleNextPage() {
if (this.currentPage == this.maxPages) {
return;
}
this.currentPage += 1;
this.handle();
}
prepare() {
let previousPageButton = document.getElementById(
"previous-page-button"
);
let nextPageButton = document.getElementById("next-page-button");
previousPageButton.addEventListener("click", () =>
this.handlePreviousPage()
);
nextPageButton.addEventListener("click", () => this.handleNextPage());
return this;
}
async handle() {
let pdf = await pdfjsLib.getDocument(this.url).promise;
let page = await pdf.getPage(this.currentPage);
this.maxPages = pdf.numPages;
let viewport = await page.getViewport({ scale: 1 });
this.canvas.height = viewport.height;
this.canvas.width = viewport.width;
page.render({
canvasContext: this.context,
viewport
});
}
}
const url = document.querySelector("meta[name='pdf-url'").content;
const canvas = document.getElementById("pdf-placeholder");
new PDF(url, canvas).prepare().handle();

View File

@ -3191,4 +3191,6 @@ return [
'minumum_php_version' => 'Minimum PHP version',
'satisfy_requirements' => 'Make sure all requirements are satisfied.',
'oops_issues' => 'Oops, something doesn\'t look right!',
'open_in_new_tab' => 'Open in new tab',
];

View File

@ -1,6 +1,11 @@
@extends('portal.ninja2020.layout.app')
@section('meta_title', ctrans('texts.view_invoice'))
@push('head')
<meta name="pdf-url" content="{{ asset($invoice->pdf_url()) }}">
<script src="{{ asset('js/vendor/pdf.js/pdf.min.js') }}"></script>
@endpush
@section('header')
{{ Breadcrumbs::render('invoices.show', $invoice) }}
@endsection
@ -37,7 +42,43 @@
</form>
@endif
<embed src="{{ asset($invoice->pdf_url()) }}#toolbar=1&navpanes=1&scrollbar=1" type="application/pdf" width="100%"
height="1180px"/>
<div class="flex items-center justify-between">
<section class="flex items-center">
<button class="input-label" id="previous-page-button">
<svg class="w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7"/>
</svg>
</button>
<button class="input-label" id="next-page-button">
<svg class="w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"/>
</svg>
</button>
</section>
<div x-data="{ open: false }" @keydown.escape="open = false" @click.away="open = false" class="relative inline-block text-left">
<div>
<button @click="open = !open" class="flex items-center text-gray-400 hover:text-gray-600 focus:outline-none focus:text-gray-600">
<svg class="h-5 w-5" fill="currentColor" viewBox="0 0 20 20">
<path d="M10 6a2 2 0 110-4 2 2 0 010 4zM10 12a2 2 0 110-4 2 2 0 010 4zM10 18a2 2 0 110-4 2 2 0 010 4z" />
</svg>
</button>
</div>
<div x-show="open" x-transition:enter="transition ease-out duration-100" x-transition:enter-start="transform opacity-0 scale-95" x-transition:enter-end="transform opacity-100 scale-100" x-transition:leave="transition ease-in duration-75" x-transition:leave-start="transform opacity-100 scale-100" x-transition:leave-end="transform opacity-0 scale-95" class="origin-top-right absolute right-0 mt-2 w-56 rounded-md shadow-lg">
<div class="rounded-md bg-white shadow-xs">
<div class="py-1">
<a target="_blank" href="{{ asset($invoice->pdf_url()) }}" class="block px-4 py-2 text-sm leading-5 text-gray-700 hover:bg-gray-100 hover:text-gray-900 focus:outline-none focus:bg-gray-100 focus:text-gray-900">{{ ctrans('texts.open_in_new_tab') }}</a>
</div>
</div>
</div>
</div>
</div>
<div class="flex justify-center">
<canvas id="pdf-placeholder" class="shadow rounded-lg bg-white mt-4 p-4"></canvas>
</div>
@endsection
@section('footer')
<script src="{{ asset('js/clients/shared/pdf.js') }}"></script>
@endsection

View File

@ -1,6 +1,11 @@
@extends('portal.ninja2020.layout.app')
@section('meta_title', ctrans('texts.view_quote'))
@push('head')
<meta name="pdf-url" content="{{ asset($quote->pdf_file_path()) }}">
<script src="{{ asset('js/vendor/pdf.js/pdf.min.js') }}"></script>
@endpush
@section('header')
{{ Breadcrumbs::render('quotes.show', $quote) }}
@endsection
@ -37,8 +42,43 @@
</form>
@endif
<embed src="{{ asset($quote->pdf_file_path()) }}#toolbar=1&navpanes=1&scrollbar=1" type="application/pdf"
width="100%"
height="1180px"/>
<div class="flex items-center justify-between">
<section class="flex items-center">
<button class="input-label" id="previous-page-button">
<svg class="w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7"/>
</svg>
</button>
<button class="input-label" id="next-page-button">
<svg class="w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"/>
</svg>
</button>
</section>
<div x-data="{ open: false }" @keydown.escape="open = false" @click.away="open = false" class="relative inline-block text-left">
<div>
<button @click="open = !open" class="flex items-center text-gray-400 hover:text-gray-600 focus:outline-none focus:text-gray-600">
<svg class="h-5 w-5" fill="currentColor" viewBox="0 0 20 20">
<path d="M10 6a2 2 0 110-4 2 2 0 010 4zM10 12a2 2 0 110-4 2 2 0 010 4zM10 18a2 2 0 110-4 2 2 0 010 4z" />
</svg>
</button>
</div>
<div x-show="open" x-transition:enter="transition ease-out duration-100" x-transition:enter-start="transform opacity-0 scale-95" x-transition:enter-end="transform opacity-100 scale-100" x-transition:leave="transition ease-in duration-75" x-transition:leave-start="transform opacity-100 scale-100" x-transition:leave-end="transform opacity-0 scale-95" class="origin-top-right absolute right-0 mt-2 w-56 rounded-md shadow-lg">
<div class="rounded-md bg-white shadow-xs">
<div class="py-1">
<a target="_blank" href="{{ asset($invoice->pdf_url()) }}" class="block px-4 py-2 text-sm leading-5 text-gray-700 hover:bg-gray-100 hover:text-gray-900 focus:outline-none focus:bg-gray-100 focus:text-gray-900">{{ ctrans('texts.open_in_new_tab') }}</a>
</div>
</div>
</div>
</div>
</div>
<div class="flex justify-center">
<canvas id="pdf-placeholder" class="shadow rounded-lg bg-white mt-4 p-4"></canvas>
</div>
@endsection
@section('footer')
<script src="{{ asset('js/clients/shared/pdf.js') }}"></script>
@endsection

6
webpack.mix.js vendored
View File

@ -31,6 +31,10 @@ mix.js("resources/js/app.js", "public/js")
.js(
"resources/js/setup/setup.js",
"public/js/setup/setup.js"
)
.js(
"resources/js/clients/shared/pdf.js",
"public/js/clients/shared/pdf.js"
);
mix.sass("resources/sass/app.scss", "public/css")
@ -44,4 +48,4 @@ mix.sass("resources/sass/app.scss", "public/css")
});
mix.version();
mix.disableNotifications();
mix.disableNotifications();