pdf package

This commit is contained in:
Shohrat 2023-10-25 21:14:04 +05:00
parent 11f666d671
commit 89f1480f35
71 changed files with 4181 additions and 0 deletions

View File

@ -0,0 +1,33 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**October version**
Add October version here.
**Plugin version**
Add plugin version here.
**Additional context**
Add any other context about the problem here.

View File

@ -0,0 +1,20 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: ''
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.

2
plugins/renatio/dynamicpdf/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
/vendor
composer.lock

View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) Renatio
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -0,0 +1,108 @@
<?php
namespace Renatio\DynamicPDF;
use Backend\Facades\Backend;
use Barryvdh\DomPDF\ServiceProvider;
use Renatio\DynamicPDF\Classes\PDFWrapper;
use Renatio\DynamicPDF\Classes\SyncTemplates;
use Renatio\DynamicPDF\Console\Demo;
use System\Classes\PluginBase;
use System\Classes\PluginManager;
use System\Models\Parameter;
class Plugin extends PluginBase
{
public function pluginDetails()
{
return [
'name' => 'renatio.dynamicpdf::lang.plugin.name',
'description' => 'renatio.dynamicpdf::lang.plugin.description',
'author' => 'Renatio',
'icon' => 'octo-icon-file-pdf-o',
'homepage' => 'https://octobercms.com/plugin/renatio-dynamicpdf',
];
}
public function boot()
{
$this->app->register(ServiceProvider::class);
$this->app->bind('dynamicpdf', function ($app) {
return new PDFWrapper($app['dompdf'], $app['config'], $app['files'], $app['view']);
});
(new SyncTemplates)->handle();
}
public function register()
{
$this->registerConsoleCommand('dynamicpdf:demo', Demo::class);
}
public function registerPermissions()
{
return [
'renatio.dynamicpdf.manage_templates' => [
'label' => 'renatio.dynamicpdf::lang.permissions.manage_templates',
'tab' => 'renatio.dynamicpdf::lang.permissions.tab',
],
'renatio.dynamicpdf.manage_layouts' => [
'label' => 'renatio.dynamicpdf::lang.permissions.manage_layouts',
'tab' => 'renatio.dynamicpdf::lang.permissions.tab',
],
];
}
public function registerMarkupTags()
{
if (PluginManager::instance()->exists('RainLab.Translate')) {
return [];
}
return [
'filters' => [
'_' => ['Lang', 'get'],
'__' => ['Lang', 'choice'],
],
];
}
public function registerSettings()
{
return [
'templates' => [
'label' => 'renatio.dynamicpdf::lang.menu.label',
'category' => 'renatio.dynamicpdf::lang.menu.category',
'icon' => 'octo-icon-file-pdf-o',
'url' => Backend::url('renatio/dynamicpdf/templates'),
'description' => 'renatio.dynamicpdf::lang.menu.description',
'permissions' => ['renatio.dynamicpdf.manage_templates'],
],
];
}
public function registerPDFTemplates()
{
if (! Parameter::get('renatio::dynamicpdf.demo')) {
return [];
}
return [
'renatio.dynamicpdf::pdf.invoice',
'renatio.dynamicpdf::pdf.header_and_footer',
];
}
public function registerPDFLayouts()
{
if (! Parameter::get('renatio::dynamicpdf.demo')) {
return [];
}
return [
'renatio.dynamicpdf::pdf.layouts.default',
'renatio.dynamicpdf::pdf.layouts.header_and_footer',
];
}
}

View File

@ -0,0 +1,571 @@
# Dynamic PDF Plugin
**Demo URL:** https://october-demo.renatio.com/backend/backend/auth/signin
**Login:** dynamicpdf
**Password:** dynamicpdf
This plugin allows developers to create and edit PDF templates with a simple user interface.
HTML to PDF converter uses [dompdf](https://github.com/dompdf/dompdf) library.
Plugin uses dompdf wrapper for Laravel [barryvdh/laravel-dompdf](https://github.com/barryvdh/laravel-dompdf).
> This plugin is fully compatible with the latest version of OctoberCMS 2.x from version 5.0.1.
> The latest version that supports OctoberCMS 1.x is version 4.0.8.
## Like this plugin?
If you like this plugin, give this plugin a Like or Make donation with [PayPal](https://www.paypal.me/mplodowski).
## My other plugins
Please check my other [plugins](https://octobercms.com/author/Renatio).
## Support
Please use [GitHub Issues Page](https://github.com/mplodowski/dynamicpdf-plugin/issues) to report any issues with
plugin.
> Reviews should not be used for getting support or reporting bugs, if you need support please use the Plugin support
> link.
Icon made by [Darius Dan](https://www.flaticon.com/authors/darius-dan)
from [www.flaticon.com](https://www.flaticon.com/).
# Documentation
## Installation
There are couple ways to install this plugin.
1. Use `php artisan plugin:install Renatio.DynamicPDF` command.
2. Use `composer require renatio/dynamicpdf-plugin` in project root. When you use this option you must
run `php artisan october:migrate` after installation.
## PDF content
PDF can be created in October using either PDF views or PDF templates. A PDF view is supplied by plugin in the file
system in the **/views** directory. Whereas a PDF template is managed using the back-end interface via *Settings > PDF >
PDF Templates*. All PDFs templates support using Twig for markup.
PDF views must be registered in the Plugin registration file with the `registerPDFTemplates` and `registerPDFLayouts`
method. This will automatically generate a PDF template and layout and allows them to be customized using the back-end
interface.
## PDF layouts views
PDF layouts views reside in the file system and the code used represents the path to the view file. For example PDF
layout with the code **author.plugin::pdf.layouts.default** would use the content in following file:
```
plugins/ <=== Plugins directory
author/ <=== "author" segment
plugin/ <=== "plugin" segment
views/ <=== View directory
pdf/ <=== "pdf" segment
layouts/ <=== "layouts" segment
default.htm <=== "default" segment
```
The content inside a PDF view file can include up to 3 sections: **configuration**, **CSS/LESS**, and **HTML markup**.
Sections are separated with the `==` sequence. For example:
```
name = "Default PDF layout"
==
body {
font-size: 16px;
}
==
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title>Document</title>
<style type="text/css" media="screen">
{{ css|raw }}
</style>
</head>
<body>
{{ content_html|raw }}
</body>
</html>
```
> **Note:** Basic Twig tags and expressions are supported in PDF views.
The **CSS/LESS** section is optional and a view can contain only the configuration and HTML markup sections.
```
name = "Default PDF layout"
==
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title>Document</title>
<style type="text/css" media="screen">
{{ css|raw }}
</style>
</head>
<body>
{{ content_html|raw }}
</body>
</html>
```
### Configuration section
The configuration section sets the PDF view parameters. The following configuration parameters are supported:
| Parameter | Description |
|-----------|----------------------------|
| **name** | the layout name, required. |
### Using PDF layouts
PDF layouts reside in the database and can be created by selecting *Settings > PDF > PDF Templates* and clicking the *
Layouts* tab. These behave just like CMS layouts, they contain the scaffold for the PDF. PDF views and templates support
the use of PDF layouts. The **code** specified in the layout is a unique identifier and cannot be changed once created.
## PDF templates views
PDF templates reside in the file system and the code used represents the path to the view file. For example PDF template
with the code **author.plugin::pdf.invoice** would use the content in following file:
```
plugins/ <=== Plugins directory
author/ <=== "author" segment
plugin/ <=== "plugin" segment
views/ <=== View directory
pdf/ <=== "pdf" segment
invoice.htm <=== "invoice" segment
```
The content inside a PDF view file can include up to 2 sections: **configuration** and **HTML markup**. Sections are
separated with the `==` sequence. For example:
```
title = "Invoice"
layout = "renatio.demo::pdf.layouts.default"
description = "Invoice template"
size = "a4"
orientation = "portrait"
==
<h1>Invoice</h1>
```
> **Note:** Basic Twig tags and expressions are supported in PDF views.
### Configuration section
The configuration section sets the PDF view parameters. The following configuration parameters are supported:
| Parameter | Description |
|-----------------|---------------------------------------------------------------|
| **title** | the template title, required. |
| **layout** | the layout code, optional. |
| **description** | the template description, optional. |
| **size** | the template paper size, optional, default `a4`. |
| **orientation** | the template paper orientation, optional, default `portrait`. |
### Using PDF templates
PDF templates reside in the database and can be created in the back-end area via *Settings > PDF > PDF Templates*.
The **code** specified in the template is a unique identifier and cannot be changed once created.
> **Note:** If the PDF template does not exist in the system, this code will attempt to find a PDF view with the same
> code.
## Registering PDF templates and layouts
PDF views can be registered as templates that are automatically generated in the back-end ready for customization. PDF
templates can be customized via the *Settings > PDF Templates* menu. The templates can be registered by adding
the `registerPDFTemplates` method of the Plugin registration class (`Plugin.php`).
```
public function registerPDFTemplates()
{
return [
'renatio.demo::pdf.invoice',
'renatio.demo::pdf.resume',
];
}
```
The method should return an array of pdf view names.
Like templates, PDF layouts can be registered by adding the `registerPDFLayouts` method of the Plugin registration
class (`Plugin.php`).
```
public function registerPDFLayouts()
{
return [
'renatio.demo::pdf.layouts.invoice',
'renatio.demo::pdf.layouts.resume',
];
}
```
The method should return an array of pdf view names.
## Usage
PDF templates and layouts can be accessed in the back-end area via *Settings > PDF > PDF Templates*.
Layouts define the PDF scaffold, that is everything that repeats on a PDF, such as a header and footer. Each layout has
unique code, optional background image, HTML content and CSS/LESS content. Not all CSS properties are supported, so
check [CSSCompatibility](https://github.com/dompdf/dompdf/wiki/CSSCompatibility).
Templates define the actual PDF content parsed from HTML.
## Configuration
The default configuration settings are set in `config/dompdf.php`. Copy this file to your own config directory to modify
the values. You can publish the config using this command:
```
php artisan vendor:publish --provider="Barryvdh\DomPDF\ServiceProvider"
```
You can still alter the dompdf options in your code before generating the PDF using dynamic methods for all options like
so:
```
PDF::loadTemplate('renatio::invoice')
->setDpi(300)
->setDefaultFont('sans-serif')
->stream();
```
Available options and their defaults:
* __rootDir__: "{app_directory}/vendor/dompdf/dompdf"
* __tempDir__: "/tmp" _(available in config/dompdf.php)_
* __fontDir__: "{app_directory}/storage/fonts/" _(available in config/dompdf.php)_
* __fontCache__: "{app_directory}/storage/fonts/" _(available in config/dompdf.php)_
* __chroot__: "{app_directory}" _(available in config/dompdf.php)_
* __logOutputFile__: "/tmp/log.htm"
* __defaultMediaType__: "screen" _(available in config/dompdf.php)_
* __defaultPaperSize__: "a4" _(available in config/dompdf.php)_
* __defaultFont__: "serif" _(available in config/dompdf.php)_
* __dpi__: 96 _(available in config/dompdf.php)_
* __fontHeightRatio__: 1.1 _(available in config/dompdf.php)_
* __isPhpEnabled__: false _(available in config/dompdf.php)_
* __isRemoteEnabled__: true _(available in config/dompdf.php)_
* __isJavascriptEnabled__: true _(available in config/dompdf.php)_
* __isHtml5ParserEnabled__: false _(available in config/dompdf.php)_
* __isFontSubsettingEnabled__: false _(available in config/dompdf.php)_
* __debugPng__: false
* __debugKeepTemp__: false
* __debugCss__: false
* __debugLayout__: false
* __debugLayoutLines__: true
* __debugLayoutBlocks__: true
* __debugLayoutInline__: true
* __debugLayoutPaddingBox__: true
* __pdfBackend__: "CPDF" _(available in config/dompdf.php)_
* __pdflibLicense__: ""
* __adminUsername__: "user"
* __adminPassword__: "password"
See [Dompdf\Options](https://github.com/dompdf/dompdf/blob/master/src/Options.php) for a list of available options.
## Methods
| Method | Description |
|---------------------------------------------------------|----------------------------------------------------------|
| loadTemplate($code, array $data = [], $encoding = null) | Load backend template |
| loadLayout($code, array $data = [], $encoding = null) | Load backend layout |
| loadHTML($string, $encoding = null) | Load HTML string |
| loadFile($file) | Load HTML string from a file |
| parseTemplate(Template $template, array $data = []) | Parse backend template using Twig |
| parseLayout(Layout $layout, array $mergeData = []) | Parse backend layout using Twig |
| getDomPDF() | Get the DomPDF instance |
| setPaper($paper, $orientation = 'portrait') | Set the paper size and orientation (default A4/portrait) |
| setWarnings($warnings) | Show or hide warnings |
| output() | Output the PDF as a string |
| save($filename) | Save the PDF to a file |
| download($filename = 'document.pdf') | Make the PDF downloadable by the user |
| stream($filename = 'document.pdf') | Return a response with the PDF to show in the browser |
All methods are available through Facade class `Renatio\DynamicPDF\Classes\PDF`.
## Tips
### Background image
To display background image added in layout use following code:
```
<body style="background: url({{ background_img }}) top left no-repeat;">
```
Background image should be at least 96 DPI size (793 x 1121 px).
If you want to use better quality image like 300 DPI (2480 x 3508 px) than you need to change template options like so:
```
return PDF::loadTemplate($model->code)
->setDpi(300)
->stream();
```
### UTF-8 support
In your layout, set the UTF-8 meta tag in `head` section:
```
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
```
If you have problems with foreign characters than try to use **DejaVu Sans** font family.
### Page breaks
You can use the CSS page-break-before/page-break-after properties to create a new page.
```
<style>
.page-break {
page-break-after: always;
}
</style>
<h1>Page 1</h1>
<div class="page-break"></div>
<h1>Page 2</h1>
```
### Open basedir restriction error
On some hosting providers there were reports about `open_basedir` restriction problems with log file. You can change
default log file destination like so:
```
return PDF::loadTemplate('renatio::invoice')
->setLogOutputFile(storage_path('temp/log.htm'))
->stream();
```
### Embed image inside PDF template
You can use absolute path for image eg. `https://app.dev/path_to_your_image`.
For this to work you must set `isRemoteEnabled` option.
```
return PDF::loadTemplate('renatio::invoice', ['file' => $file])
->setIsRemoteEnabled(true)
->stream();
```
I assume that `$file` is instance of `October\Rain\Database\Attach\File`.
Then in the template you can use following example code:
```
{{ file.getPath }}
{{ file.getLocalPath }}
{{ file.getThumb(200, 200, {'crop' => true}) }}
```
> For retrieving stylesheets or images via http following PHP setting must be enabled `allow_url_fopen`.
When `allow_url_fopen` is disabled on server try to use relative path. You can use October `getLocalPath` function on
the file object to retrieve it.
### Download PDF via Ajax response
OctoberCMS ajax framework cannot handle this type of response.
Recommended approach is to save PDF file locally and return redirect to PDF file.
### Page numbers
Page numbers can be generated using PHP. Inline PHP is disabled by default, because it can be a security risk. You can
enable inline PHP using `setIsPhpEnabled` method.
```
return PDF::loadTemplate('renatio::invoice')
->setIsRemoteEnabled(true)
->setIsPhpEnabled(true)
->stream();
```
After that you must place following code after `<body>` tag of the layout file.
```
<script type="text/php">
if (isset($pdf)) {
$size = 9;
$color = [0,0,0];
$font = $fontMetrics->getFont('Open Sans');
$textHeight = $fontMetrics->getFontHeight($font, $size);
$width = $fontMetrics->getTextWidth('Page 1 of 2', $font, $size);
$foot = $pdf->open_object();
$w = $pdf->get_width();
$h = $pdf->get_height();
$y = $h - $textHeight - 13;
$pdf->close_object();
$pdf->add_object($foot, 'all');
$text = "Page {PAGE_NUM} of {PAGE_COUNT}";
// Center the text
$pdf->page_text($w / 2 - $width / 2, $y, $text, $font, $size, $color);
}
</script>
```
## Examples
### Demo examples
There is a console command that will enable demo templates and layouts.
```
php artisan dynamicpdf:demo
```
To disable demo run following command:
```
php artisan dynamicpdf:demo --disable
```
The first example shows invoice with custom font and image embed.
The second example shows usage of header & footer, page break, page numbers and full background image.
### Render PDF in browser
```
use Renatio\DynamicPDF\Classes\PDF; // import facade
public function pdf()
{
$templateCode = 'renatio::invoice'; // unique code of the template
$data = ['name' => 'John Doe']; // optional data used in template
return PDF::loadTemplate($templateCode, $data)->stream('download.pdf');
}
```
Where `$templateCode` is an unique code specified when creating the template, `$data` is optional array of twig fields
which will be replaced in template.
In HTML template you can use `{{ name }}` to output `John Doe`.
### Download PDF
```
use Renatio\DynamicPDF\Classes\PDF;
public function pdf()
{
return PDF::loadTemplate('renatio::invoice')->download('download.pdf');
}
```
### Fluent interface
You can chain the methods:
```
return PDF::loadTemplate('renatio::invoice')
->save('/path-to/my_stored_file.pdf')
->stream();
```
### Change paper size and orientation
```
return PDF::loadTemplate('renatio::invoice')
->setPaper('a4', 'landscape')
->stream();
```
Available [paper sizes](https://github.com/dompdf/dompdf/blob/master/src/Adapter/CPDF.php#L40).
### PDF on CMS page
To display PDF on CMS page you can use PHP section of the page like so:
```
use Renatio\DynamicPDF\Classes\PDF;
function onStart()
{
return PDF::loadTemplate('renatio::invoice')->stream();
}
```
### Header and footer on every page
```
<html>
<head>
<style>
@page { margin: 100px 25px; }
header { position: fixed; top: -60px; left: 0px; right: 0px; background-color: lightblue; height: 50px; }
footer { position: fixed; bottom: -60px; left: 0px; right: 0px; background-color: lightblue; height: 50px; }
p { page-break-after: always; }
p:last-child { page-break-after: never; }
</style>
</head>
<body>
<header>header on each page</header>
<footer>footer on each page</footer>
<main>
<p>page1</p>
<p>page2</p>
</main>
</body>
</html>
```
### Using custom fonts
Plugin provides "Open Sans" font, which can be imported in Layout CSS section.
```
@font-face {
font-family: 'Open Sans';
src: url({{ 'plugins/renatio/dynamicpdf/assets/fonts/OpenSans-Regular.ttf'|app }});
}
@font-face {
font-family: 'Open Sans';
font-weight: bold;
src: url({{ 'plugins/renatio/dynamicpdf/assets/fonts/OpenSans-Bold.ttf'|app }});
}
@font-face {
font-family: 'Open Sans';
font-style: italic;
src: url({{ 'plugins/renatio/dynamicpdf/assets/fonts/OpenSans-Italic.ttf'|app }});
}
@font-face {
font-family: 'Open Sans';
font-style: italic;
font-weight: bold;
src: url({{ 'plugins/renatio/dynamicpdf/assets/fonts/OpenSans-BoldItalic.ttf'|app }});
}
body {
font-family: 'Open Sans', sans-serif;
font-size: 16px;
}
```

View File

@ -0,0 +1,59 @@
# Upgrade guide
## Upgrading To 1.1.0
Plugin requires October build 300+.
## Upgrading To 2.0.0
`PDFTemplate::render()` method was removed. Please switch to `Renatio\DynamicPDF\Classes\PDF` facade.
## Upgrading To 2.1.0
Method `setOrientation` was removed. Use `setPaper` instead.
## Upgrading To 2.1.1
Plugin requires **Stable** version of October and PHP >=5.5.9.
## Upgrading To 3.0.0
Plugin requires OctoberCMS build 420+ with Laravel 5.5 and PHP >=7.0.
## Upgrading To 4.0.0
Plugin requires PHP >=7.1 to work with the latest version of [dompdf](https://github.com/dompdf/dompdf) library.
For October composer based installation you must manually update project composer.json file to use at least PHP 7.1:
```
"config": {
"preferred-install": "dist",
"platform": {
"php": "7.1"
}
},
```
After this change run `composer update` command.
## Upgrading To 4.0.8
This is the latest version with support for October 1.x.
Using `setOptions` method to change dompdf options is no longer recommended. This will cause to override all laravel
dompdf configuration and use only specified by method argument and dompdf defaults for rest options not set by a
developer.
Instead of using this method, please use dynamic method call for option you would like to change. Please read more
in [documentation](https://github.com/mplodowski/dynamicpdf-plugin/blob/master/README.md#configuration-configuration).
## Upgrading To 5.0.1
Plugin requires OctoberCMS v2.1.x with Laravel 6 and PHP >=7.2.
## Upgrading To 6.0.0
Plugin requires October CMS version 3.0 or higher, Laravel 9.0 or higher and PHP >=8.0.
Drop support for October CMS version 2.x.

View File

@ -0,0 +1,766 @@
/*! tailwindcss v2.2.19 | MIT License | https://tailwindcss.com */
/*! modern-normalize v1.1.0 | MIT License | https://github.com/sindresorhus/modern-normalize */
/*
Document
========
*/
/**
Use a better box model (opinionated).
*/
*,
::before,
::after {
box-sizing: border-box;
}
/**
Use a more readable tab size (opinionated).
*/
html {
-moz-tab-size: 4;
tab-size: 4;
}
/**
1. Correct the line height in all browsers.
2. Prevent adjustments of font size after orientation changes in iOS.
*/
html {
line-height: 1.15;
/* 1 */
-webkit-text-size-adjust: 100%;
/* 2 */
}
/*
Sections
========
*/
/**
Remove the margin in all browsers.
*/
body {
margin: 0;
}
/**
Improve consistency of default fonts in all browsers. (https://github.com/sindresorhus/modern-normalize/issues/3)
*/
body {
font-family:
system-ui,
-apple-system, /* Firefox supports this but not yet `system-ui` */
'Segoe UI',
Roboto,
Helvetica,
Arial,
sans-serif,
'Apple Color Emoji',
'Segoe UI Emoji';
}
/*
Grouping content
================
*/
/**
1. Add the correct height in Firefox.
2. Correct the inheritance of border color in Firefox. (https://bugzilla.mozilla.org/show_bug.cgi?id=190655)
*/
hr {
height: 0;
/* 1 */
color: inherit;
/* 2 */
}
/*
Text-level semantics
====================
*/
/**
Add the correct text decoration in Chrome, Edge, and Safari.
*/
abbr[title] {
text-decoration: underline dotted;
}
/**
Add the correct font weight in Edge and Safari.
*/
b,
strong {
font-weight: bolder;
}
/**
1. Improve consistency of default fonts in all browsers. (https://github.com/sindresorhus/modern-normalize/issues/3)
2. Correct the odd 'em' font sizing in all browsers.
*/
code,
kbd,
samp,
pre {
font-family:
ui-monospace,
SFMono-Regular,
Consolas,
'Liberation Mono',
Menlo,
monospace;
/* 1 */
font-size: 1em;
/* 2 */
}
/**
Add the correct font size in all browsers.
*/
small {
font-size: 80%;
}
/**
Prevent 'sub' and 'sup' elements from affecting the line height in all browsers.
*/
sub,
sup {
font-size: 75%;
line-height: 0;
position: relative;
vertical-align: baseline;
}
sub {
bottom: -0.25em;
}
sup {
top: -0.5em;
}
/*
Tabular data
============
*/
/**
1. Remove text indentation from table contents in Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=999088, https://bugs.webkit.org/show_bug.cgi?id=201297)
2. Correct table border color inheritance in all Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=935729, https://bugs.webkit.org/show_bug.cgi?id=195016)
*/
table {
text-indent: 0;
/* 1 */
border-color: inherit;
/* 2 */
}
/*
Forms
=====
*/
/**
1. Change the font styles in all browsers.
2. Remove the margin in Firefox and Safari.
*/
button,
input,
optgroup,
select,
textarea {
font-family: inherit;
/* 1 */
font-size: 100%;
/* 1 */
line-height: 1.15;
/* 1 */
margin: 0;
/* 2 */
}
/**
Remove the inheritance of text transform in Edge and Firefox.
1. Remove the inheritance of text transform in Firefox.
*/
button,
select {
/* 1 */
text-transform: none;
}
/**
Correct the inability to style clickable types in iOS and Safari.
*/
button,
[type='button'] {
-webkit-appearance: button;
}
/**
Remove the inner border and padding in Firefox.
*/
/**
Restore the focus styles unset by the previous rule.
*/
/**
Remove the additional ':invalid' styles in Firefox.
See: https://github.com/mozilla/gecko-dev/blob/2f9eacd9d3d995c937b4251a5557d95d494c9be1/layout/style/res/forms.css#L728-L737
*/
/**
Remove the padding so developers are not caught out when they zero out 'fieldset' elements in all browsers.
*/
legend {
padding: 0;
}
/**
Add the correct vertical alignment in Chrome and Firefox.
*/
progress {
vertical-align: baseline;
}
/**
Correct the cursor style of increment and decrement buttons in Safari.
*/
/**
1. Correct the odd appearance in Chrome and Safari.
2. Correct the outline style in Safari.
*/
/**
Remove the inner padding in Chrome and Safari on macOS.
*/
/**
1. Correct the inability to style clickable types in iOS and Safari.
2. Change font properties to 'inherit' in Safari.
*/
/*
Interactive
===========
*/
/*
Add the correct display in Chrome and Safari.
*/
summary {
display: list-item;
}
/**
* Manually forked from SUIT CSS Base: https://github.com/suitcss/base
* A thin layer on top of normalize.css that provides a starting point more
* suitable for web applications.
*/
/**
* Removes the default spacing and border for appropriate elements.
*/
blockquote,
dl,
dd,
h1,
h2,
h3,
h4,
h5,
h6,
hr,
figure,
p,
pre {
margin: 0;
}
button {
background-color: transparent;
background-image: none;
}
fieldset {
margin: 0;
padding: 0;
}
ol,
ul {
list-style: none;
margin: 0;
padding: 0;
}
/**
* Tailwind custom reset styles
*/
/**
* 1. Use the user's configured `sans` font-family (with Tailwind's default
* sans-serif font stack as a fallback) as a sane default.
* 2. Use Tailwind's default "normal" line-height so the user isn't forced
* to override it to ensure consistency even when using the default theme.
*/
html {
font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
/* 1 */
line-height: 1.5;
/* 2 */
}
/**
* Inherit font-family and line-height from `html` so users can set them as
* a class directly on the `html` element.
*/
body {
font-family: inherit;
line-height: inherit;
}
/**
* 1. Prevent padding and border from affecting element width.
*
* We used to set this in the html element and inherit from
* the parent element for everything else. This caused issues
* in shadow-dom-enhanced elements like <details> where the content
* is wrapped by a div with box-sizing set to `content-box`.
*
* https://github.com/mozdevs/cssremedy/issues/4
*
*
* 2. Allow adding a border to an element by just adding a border-width.
*
* By default, the way the browser specifies that an element should have no
* border is by setting it's border-style to `none` in the user-agent
* stylesheet.
*
* In order to easily add borders to elements by just setting the `border-width`
* property, we change the default border-style for all elements to `solid`, and
* use border-width to hide them instead. This way our `border` utilities only
* need to set the `border-width` property instead of the entire `border`
* shorthand, making our border utilities much more straightforward to compose.
*
* https://github.com/tailwindcss/tailwindcss/pull/116
*/
*,
::before,
::after {
box-sizing: border-box;
/* 1 */
border-width: 0;
/* 2 */
border-style: solid;
/* 2 */
border-color: currentColor;
/* 2 */
}
/*
* Ensure horizontal rules are visible by default
*/
hr {
border-top-width: 1px;
}
/**
* Undo the `border-style: none` reset that Normalize applies to images so that
* our `border-{width}` utilities have the expected effect.
*
* The Normalize reset is unnecessary for us since we default the border-width
* to 0 on all elements.
*
* https://github.com/tailwindcss/tailwindcss/issues/362
*/
img {
border-style: solid;
}
textarea {
resize: vertical;
}
input::placeholder,
textarea::placeholder {
opacity: 1;
color: #9ca3af;
}
button {
cursor: pointer;
}
/**
* Override legacy focus reset from Normalize with modern Firefox focus styles.
*
* This is actually an improvement over the new defaults in Firefox in our testing,
* as it triggers the better focus styles even for links, which still use a dotted
* outline in Firefox by default.
*/
table {
border-collapse: collapse;
}
h1,
h2,
h3,
h4,
h5,
h6 {
font-size: inherit;
font-weight: inherit;
}
/**
* Reset links to optimize for opt-in styling instead of
* opt-out.
*/
a {
color: inherit;
text-decoration: inherit;
}
/**
* Reset form element properties that are easy to forget to
* style explicitly so you don't inadvertently introduce
* styles that deviate from your design system. These styles
* supplement a partial reset that is already applied by
* normalize.css.
*/
button,
input,
optgroup,
select,
textarea {
padding: 0;
line-height: inherit;
color: inherit;
}
/**
* Use the configured 'mono' font family for elements that
* are expected to be rendered with a monospace font, falling
* back to the system monospace stack if there is no configured
* 'mono' font family.
*/
pre,
code,
kbd,
samp {
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
}
/**
* 1. Make replaced elements `display: block` by default as that's
* the behavior you want almost all of the time. Inspired by
* CSS Remedy, with `svg` added as well.
*
* https://github.com/mozdevs/cssremedy/issues/14
*
* 2. Add `vertical-align: middle` to align replaced elements more
* sensibly by default when overriding `display` by adding a
* utility like `inline`.
*
* This can trigger a poorly considered linting error in some
* tools but is included by design.
*
* https://github.com/jensimmons/cssremedy/issues/14#issuecomment-634934210
*/
img,
svg,
video,
canvas,
audio,
iframe,
embed,
object {
display: block;
/* 1 */
vertical-align: middle;
/* 2 */
}
/**
* Constrain images and videos to the parent width and preserve
* their intrinsic aspect ratio.
*
* https://github.com/mozdevs/cssremedy/issues/14
*/
img,
video {
max-width: 100%;
height: auto;
}
/**
* Ensure the default browser behavior of the `hidden` attribute.
*/
*, ::before, ::after {
border-color: #e5e7eb;
}
.fixed {
position: fixed;
}
.top-0 {
top: 0px;
}
.bottom-0 {
bottom: 0px;
}
.float-right {
float: right;
}
.float-left {
float: left;
}
.clear-both {
clear: both;
}
.my-8 {
margin-top: 2rem;
margin-bottom: 2rem;
}
.mt-4 {
margin-top: 1rem;
}
.mt-8 {
margin-top: 2rem;
}
.mt-20 {
margin-top: 5rem;
}
.mb-2 {
margin-bottom: 0.5rem;
}
.mb-4 {
margin-bottom: 1rem;
}
.table {
display: table;
}
.h-24 {
height: 6rem;
}
.h-32 {
height: 8rem;
}
.w-16 {
width: 4rem;
}
.w-1\/2 {
width: 50%;
}
.w-full {
width: 100%;
}
.border-2 {
border-width: 2px;
}
.border-b {
border-bottom-width: 1px;
}
.border-solid {
border-style: solid;
}
.border-gray-700 {
border-color: #374151;
}
.border-gray-800 {
border-color: #1f2937;
}
.bg-left-top {
background-position: left top;
}
.bg-no-repeat {
background-repeat: no-repeat;
}
.p-16 {
padding: 4rem;
}
.px-12 {
padding-left: 3rem;
padding-right: 3rem;
}
.py-2 {
padding-top: 0.5rem;
padding-bottom: 0.5rem;
}
.py-4 {
padding-top: 1rem;
padding-bottom: 1rem;
}
.pt-36 {
padding-top: 9rem;
}
.pb-1 {
padding-bottom: 0.25rem;
}
.pb-4 {
padding-bottom: 1rem;
}
.pb-20 {
padding-bottom: 5rem;
}
.text-left {
text-align: left;
}
.text-center {
text-align: center;
}
.text-right {
text-align: right;
}
.text-sm {
font-size: 0.875rem;
line-height: 1.25rem;
}
.text-lg {
font-size: 1.125rem;
line-height: 1.75rem;
}
.text-xl {
font-size: 1.25rem;
line-height: 1.75rem;
}
.text-2xl {
font-size: 1.5rem;
line-height: 2rem;
}
.text-3xl {
font-size: 1.875rem;
line-height: 2.25rem;
}
.text-4xl {
font-size: 2.25rem;
line-height: 2.5rem;
}
.font-normal {
font-weight: 400;
}
.font-bold {
font-weight: 700;
}
.uppercase {
text-transform: uppercase;
}
.leading-none {
line-height: 1;
}
.text-gray-400 {
color: #9ca3af;
}
.text-gray-500 {
color: #6b7280;
}
.text-gray-700 {
color: #374151;
}
.text-gray-800 {
color: #1f2937;
}
@media (min-width: 640px) {
}
@media (min-width: 768px) {
}
@media (min-width: 1024px) {
}
@media (min-width: 1280px) {
}
@media (min-width: 1536px) {
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 148 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

@ -0,0 +1,161 @@
module.exports = {
purge: [
'./plugins/renatio/dynamicpdf/views/pdf/*.htm',
'./plugins/renatio/dynamicpdf/views/pdf/layouts/*.htm',
],
darkMode: false,
theme: {
extend: {
screens: {},
},
},
variants: {
extend: {},
},
plugins: [],
corePlugins: {
accessibility: false,
alignContent: false,
alignItems: false,
alignSelf: false,
animation: false,
appearance: false,
backdropBlur: false,
backdropBrightness: false,
backdropContrast: false,
backdropFilter: false,
backdropGrayscale: false,
backdropHueRotate: false,
backdropInvert: false,
backdropOpacity: false,
backdropSaturate: false,
backdropSepia: false,
backgroundAttachment: [],
backgroundBlendMode: false,
backgroundClip: false,
backgroundColor: [],
backgroundImage: [],
backgroundOpacity: false,
backgroundPosition: [],
backgroundRepeat: [],
backgroundSize: [],
backgroundOrigin: [],
blur: false,
borderCollapse: [],
borderColor: [],
borderOpacity: false,
borderRadius: [],
borderStyle: [],
borderWidth: [],
boxDecorationBreak: false,
boxShadow: false,
boxSizing: false,
brightness: false,
clear: [],
container: false,
contrast: false,
cursor: false,
display: [],
divideColor: false,
divideOpacity: false,
divideStyle: false,
divideWidth: false,
dropShadow: false,
fill: false,
filter: false,
flex: false,
flexDirection: false,
flexGrow: false,
flexShrink: false,
flexWrap: false,
float: [],
fontFamily: [],
fontSize: [],
fontSmoothing: false,
fontStyle: [],
fontVariantNumeric: false,
fontWeight: [],
gap: false,
gradientColorStops: false,
grayscale: false,
gridAutoColumns: false,
gridAutoFlow: false,
gridAutoRows: false,
gridColumn: false,
gridColumnEnd: false,
gridColumnStart: false,
gridRow: false,
gridRowEnd: false,
gridRowStart: false,
gridTemplateColumns: false,
gridTemplateRows: false,
height: [],
hueRotate: false,
inset: [],
invert: false,
isolation: false,
justifyContent: false,
justifyItems: false,
justifySelf: false,
letterSpacing: [],
lineHeight: [],
listStylePosition: [],
listStyleType: [],
margin: [],
maxHeight: [],
maxWidth: [],
minHeight: [],
minWidth: [],
mixBlendMode: false,
objectFit: false,
objectPosition: false,
opacity: false,
order: false,
outline: [],
overflow: [],
overscrollBehavior: false,
padding: [],
placeContent: false,
placeItems: false,
placeSelf: false,
placeholderColor: false,
placeholderOpacity: false,
pointerEvents: false,
position: [],
resize: false,
ringColor: false,
ringOffsetColor: false,
ringOffsetWidth: false,
ringOpacity: false,
ringWidth: false,
rotate: false,
saturate: false,
scale: false,
sepia: false,
skew: false,
space: false,
stroke: false,
strokeWidth: false,
tableLayout: [],
textAlign: [],
textColor: [],
textDecoration: [],
textOpacity: false,
textOverflow: [],
textTransform: [],
transform: false,
transformOrigin: false,
transitionDelay: false,
transitionDuration: false,
transitionProperty: false,
transitionTimingFunction: false,
translate: false,
userSelect: false,
verticalAlign: [],
visibility: [],
whitespace: [],
width: [],
wordBreak: [],
zIndex: [],
}
}

View File

@ -0,0 +1,13 @@
<?php
namespace Renatio\DynamicPDF\Classes;
use Barryvdh\DomPDF\Facade;
class PDF extends Facade
{
protected static function getFacadeAccessor()
{
return 'dynamicpdf';
}
}

View File

@ -0,0 +1,78 @@
<?php
namespace Renatio\DynamicPDF\Classes;
use October\Rain\Support\Traits\Singleton;
use System\Classes\PluginManager;
class PDFManager
{
use Singleton;
protected $registeredTemplates;
protected $registeredLayouts;
public function loadRegisteredTemplates()
{
$plugins = PluginManager::instance()->getPlugins();
foreach ($plugins as $plugin) {
if (method_exists($plugin, 'registerPDFLayouts')) {
$layouts = $plugin->registerPDFLayouts();
if (is_array($layouts)) {
$this->registerLayouts($layouts);
}
}
if (method_exists($plugin, 'registerPDFTemplates')) {
$templates = $plugin->registerPDFTemplates();
if (is_array($templates)) {
$this->registerTemplates($templates);
}
}
}
}
public function listRegisteredLayouts()
{
if ($this->registeredLayouts === null) {
$this->loadRegisteredTemplates();
}
return $this->registeredLayouts;
}
public function listRegisteredTemplates()
{
if ($this->registeredTemplates === null) {
$this->loadRegisteredTemplates();
}
return $this->registeredTemplates;
}
public function registerLayouts(array $definitions)
{
if (! $this->registeredLayouts) {
$this->registeredLayouts = [];
}
$definitions = array_combine($definitions, $definitions);
$this->registeredLayouts = $definitions + $this->registeredLayouts;
}
public function registerTemplates(array $definitions)
{
if (! $this->registeredTemplates) {
$this->registeredTemplates = [];
}
$definitions = array_combine($definitions, $definitions);
$this->registeredTemplates = $definitions + $this->registeredTemplates;
}
}

View File

@ -0,0 +1,45 @@
<?php
namespace Renatio\DynamicPDF\Classes;
use File;
use View;
class PDFParser
{
const SECTION_SEPARATOR = '==';
public static function parse($content)
{
$sections = preg_split('/^={2,}\s*/m', $content, -1);
$count = count($sections);
foreach ($sections as &$section) {
$section = trim($section);
}
$result = [
'settings' => [],
'css' => null,
'html' => null,
];
if ($count >= 3) {
$result['settings'] = parse_ini_string($sections[0], true);
$result['css'] = $sections[1];
$result['html'] = $sections[2];
} elseif ($count == 2) {
$result['settings'] = parse_ini_string($sections[0], true);
$result['html'] = $sections[1];
} elseif ($count == 1) {
$result['html'] = $sections[0];
}
return $result;
}
public static function sections($path)
{
return PDFParser::parse(File::get(View::make($path)->getPath()));
}
}

View File

@ -0,0 +1,108 @@
<?php
namespace Renatio\DynamicPDF\Classes;
use Barryvdh\DomPDF\PDF;
use Cms\Classes\Controller;
use Exception;
use October\Rain\Support\Facades\Twig;
use RainLab\Translate\Classes\Translator;
use RainLab\Translate\Models\Message;
use Renatio\DynamicPDF\Models\Layout;
use Renatio\DynamicPDF\Models\Template;
use System\Classes\PluginManager;
class PDFWrapper extends PDF
{
public function __call($method, $args)
{
$options = $this->getDomPDF()->getOptions();
if (method_exists($options, $method)) {
call_user_func_array([$options, $method], $args);
}
return $this;
}
public function loadTemplate($code, $data = [], $encoding = null)
{
$template = Template::byCode($code);
$this->loadHTML(
$this->parseTemplate($template, $data),
$encoding
);
if ($template->size) {
$this->setPaper($template->size, $template->orientation ?? 'portrait');
}
return $this;
}
public function loadLayout($code, $data = [], $encoding = null)
{
$this->loadHTML(
$this->parseLayout(Layout::byCode($code), $data),
$encoding
);
return $this;
}
public function parseTemplate($template, $data = [])
{
$this->setLocale();
$html = $this->parseMarkup($template->content_html, $data);
if (! $template->layout) {
return $html;
}
return $this->parseLayout(
$template->layout,
array_merge(['content_html' => $html], $data)
);
}
public function parseLayout($layout, $data = [])
{
$this->setLocale();
return $this->parseMarkup(
$layout->content_html,
$this->layoutData($layout, $data)
);
}
protected function setLocale()
{
if (! PluginManager::instance()->exists('RainLab.Translate')) {
return;
}
Message::$locale = Translator::instance()->getLocale();
}
protected function layoutData($layout, $data)
{
return array_merge([
'background_img' => $layout->background_img ? $layout->background_img->getPath() : null,
'css' => $layout->getCSS(),
], $data);
}
protected function parseMarkup($markup, $data)
{
try {
$twig = (new Controller)->getTwig();
$template = $twig->createTemplate($markup);
return $template->render($data);
} catch (Exception $e) {
return Twig::parse($markup, $data);
}
}
}

View File

@ -0,0 +1,96 @@
<?php
namespace Renatio\DynamicPDF\Classes;
use Exception;
use Renatio\DynamicPDF\Models\Layout;
use Renatio\DynamicPDF\Models\Template;
class SyncTemplates
{
public function handle()
{
try {
$this->checkFontsDir();
$this->checkPublicDir();
$this->createLayouts();
$registeredTemplates = PDFManager::instance()->listRegisteredTemplates();
if (! $registeredTemplates) {
return;
}
$dbTemplates = Template::lists('is_custom', 'code');
$this->clearNonCustomizedTemplates($dbTemplates, $registeredTemplates);
$newTemplates = array_diff_key($registeredTemplates, $dbTemplates);
$this->createTemplates($newTemplates);
} catch (Exception $e) {
//
}
}
protected function createLayouts()
{
$registeredLayouts = PDFManager::instance()->listRegisteredLayouts();
if (! $registeredLayouts) {
return;
}
$dbLayouts = Layout::lists('code', 'code');
foreach ($registeredLayouts as $code) {
if (array_key_exists($code, $dbLayouts)) {
continue;
}
$layout = new Layout;
$layout->code = $code;
$layout->is_locked = true;
$layout->fillFromView($code);
$layout->save();
}
}
protected function clearNonCustomizedTemplates($dbTemplates, $registeredTemplates)
{
foreach ($dbTemplates as $code => $isCustom) {
if ($isCustom) {
continue;
}
if (! array_key_exists($code, $registeredTemplates)) {
Template::whereCode($code)->delete();
}
}
}
protected function createTemplates($templates)
{
foreach ($templates as $code) {
$template = new Template;
$template->fillFromView($code);
$template->forceSave();
}
}
protected function checkFontsDir()
{
if (! file_exists(config('dompdf.defines.font_dir'))) {
mkdir(config('dompdf.defines.font_dir'), 0755, true);
}
}
protected function checkPublicDir()
{
if (! file_exists('public')) {
mkdir('public', 0755, true);
}
}
}

View File

@ -0,0 +1,25 @@
{
"name": "renatio/dynamicpdf-plugin",
"type": "october-plugin",
"description": "October HTML to PDF converter using dompdf library.",
"homepage": "https://octobercms.com/plugin/renatio-dynamicpdf",
"keywords": [
"octobercms-plugin",
"octobercms",
"php",
"laravel",
"pdf",
"dompdf"
],
"license": "MIT",
"authors": [
{
"name": "Michal Plodowski",
"email": "michal.plodowski@gmail.com"
}
],
"require": {
"barryvdh/laravel-dompdf": "^1.0",
"composer/installers": "~1.0"
}
}

View File

@ -0,0 +1,49 @@
<?php
namespace Renatio\DynamicPDF\Console;
use Illuminate\Console\Command;
use Renatio\DynamicPDF\Models\Layout;
use Renatio\DynamicPDF\Models\Template;
use System\Classes\PluginManager;
use System\Models\Parameter;
class Demo extends Command
{
protected $signature = 'dynamicpdf:demo {--disable}';
protected $description = 'Enable/Disable PDF demo templates.';
public function handle()
{
if ($this->option('disable')) {
$this->disableDemo();
} else {
$this->enableDemo();
}
}
protected function enableDemo()
{
Parameter::set('renatio::dynamicpdf.demo', 1);
$this->info(e(trans('renatio.dynamicpdf::lang.demo.enabled')));
}
protected function disableDemo()
{
$plugin = PluginManager::instance()->findByNamespace('Renatio.DynamicPDF');
foreach ($plugin->registerPDFTemplates() as $template) {
Template::where('code', $template)->delete();
}
foreach ($plugin->registerPDFLayouts() as $layout) {
Layout::where('code', $layout)->delete();
}
Parameter::set('renatio::dynamicpdf.demo', 0);
$this->info(e(trans('renatio.dynamicpdf::lang.demo.disabled')));
}
}

View File

@ -0,0 +1,67 @@
<?php
namespace Renatio\DynamicPDF\Controllers;
use Backend\Behaviors\FormController;
use Backend\Classes\Controller;
use Backend\Facades\BackendMenu;
use October\Rain\Exception\ApplicationException;
use October\Rain\Support\Facades\Flash;
use Renatio\DynamicPDF\Classes\PDF;
use System\Classes\SettingsManager;
class Layouts extends Controller
{
public $requiredPermissions = ['renatio.dynamicpdf.manage_layouts'];
public $implement = [
FormController::class,
];
public $formConfig = 'config_form.yaml';
public function __construct()
{
parent::__construct();
BackendMenu::setContext('October.System', 'system', 'settings');
SettingsManager::setContext('Renatio.DynamicPDF', 'templates');
}
public function previewPdf($id)
{
$this->pageTitle = e(trans('renatio.dynamicpdf::lang.templates.preview_pdf'));
try {
$model = $this->formFindModelObject($id);
} catch (ApplicationException $e) {
return $this->handleError($e);
}
return PDF::loadLayout($model->code)
->setLogOutputFile(storage_path('temp/log.htm'))
->setIsRemoteEnabled(true)
->setDpi(300)
->setIsPhpEnabled(true)
->stream();
}
public function html($id)
{
$model = $this->formFindModelObject($id);
return response($model->html);
}
public function update_onResetDefault($recordId)
{
$model = $this->formFindModelObject($recordId);
$model->fillFromCode();
$model->save();
Flash::success(e(trans('backend::lang.form.reset_success')));
return redirect()->refresh();
}
}

View File

@ -0,0 +1,88 @@
<?php
namespace Renatio\DynamicPDF\Controllers;
use Backend\Behaviors\FormController;
use Backend\Behaviors\ListController;
use Backend\Classes\Controller;
use Backend\Facades\BackendMenu;
use October\Rain\Exception\ApplicationException;
use October\Rain\Support\Facades\Flash;
use Renatio\DynamicPDF\Classes\PDF;
use System\Classes\SettingsManager;
class Templates extends Controller
{
public $requiredPermissions = ['renatio.dynamicpdf.manage_templates'];
public $implement = [
ListController::class,
FormController::class,
];
public $listConfig = [
'templates' => 'config_templates_list.yaml',
'layouts' => 'config_layouts_list.yaml',
];
public $formConfig = 'config_form.yaml';
public function __construct()
{
parent::__construct();
BackendMenu::setContext('October.System', 'system', 'settings');
SettingsManager::setContext('Renatio.DynamicPDF', 'templates');
}
public function index($tab = null)
{
$this->asExtension('ListController')->index();
$this->bodyClass = 'compact-container';
$this->vars['activeTab'] = $tab ?: 'templates';
}
public function formBeforeSave($model)
{
$model->is_custom = 1;
}
public function previewPdf($id)
{
$this->pageTitle = e(trans('renatio.dynamicpdf::lang.templates.preview_pdf'));
try {
$model = $this->formFindModelObject($id);
} catch (ApplicationException $e) {
return $this->handleError($e);
}
return PDF::loadTemplate($model->code)
->setLogOutputFile(storage_path('temp/log.htm'))
->setIsRemoteEnabled(true)
->setDpi(300)
->setIsPhpEnabled(true)
->stream();
}
public function html($id)
{
$model = $this->formFindModelObject($id);
return response($model->html);
}
public function update_onResetDefault($recordId)
{
$model = $this->formFindModelObject($recordId);
$model->fillFromCode();
$model->is_custom = 0;
$model->save();
Flash::success(e(trans('backend::lang.form.reset_success')));
return redirect()->refresh();
}
}

View File

@ -0,0 +1,31 @@
# ===================================
# Form Behavior Config
# ===================================
# Record name
name: renatio.dynamicpdf::lang.layout.menu_label
# Model Form Field configuration
form: $/renatio/dynamicpdf/models/layout/fields.yaml
# Model Class name
modelClass: Renatio\DynamicPDF\Models\Layout
# Default redirect location
defaultRedirect: renatio/dynamicpdf/templates/index/layouts
# Create page
create:
title: renatio.dynamicpdf::lang.layout.create_layout
redirect: renatio/dynamicpdf/layouts/update/:id
redirectClose: renatio/dynamicpdf/templates/index/layouts
# Update page
update:
title: renatio.dynamicpdf::lang.layout.edit_layout
redirect: renatio/dynamicpdf/templates/index/layouts
redirectClose: renatio/dynamicpdf/templates/index/layouts
# Preview page
preview:
title: renatio.dynamicpdf::lang.templates.preview_html

View File

@ -0,0 +1,58 @@
<?php Block::put('breadcrumb') ?>
<ul>
<li>
<a href="<?= Backend::url('renatio/dynamicpdf/templates/index/layouts') ?>">
<?= e(trans('renatio.dynamicpdf::lang.layouts.label')) ?>
</a>
</li>
<li><?= e($this->pageTitle) ?></li>
</ul>
<?php Block::endPut() ?>
<?php if (! $this->fatalError) : ?>
<?= Form::open(['class' => 'layout']) ?>
<div class="layout-row">
<?= $this->formRender() ?>
</div>
<div class="form-buttons pt-4">
<div class="loading-indicator-container">
<button type="submit"
data-request="onSave"
data-hotkey="ctrl+s, cmd+s"
data-load-indicator="<?= e(trans('backend::lang.form.creating_name',
['name' => $formRecordName])) ?>"
class="btn btn-primary">
<?= e(trans('backend::lang.form.create')) ?>
</button>
<button type="button"
data-request="onSave"
data-request-data="close:1"
data-hotkey="ctrl+enter, cmd+enter"
data-load-indicator="<?= e(trans('backend::lang.form.creating_name',
['name' => $formRecordName])) ?>"
class="btn btn-default">
<?= e(trans('backend::lang.form.create_and_close')) ?>
</button>
<span class="btn-text">
<?= e(trans('backend::lang.form.or')) ?>
<a href="<?= Backend::url('renatio/dynamicpdf/templates/index/layouts') ?>">
<?= e(trans('backend::lang.form.cancel')) ?>
</a>
</span>
</div>
</div>
<?= Form::close() ?>
<?php else: ?>
<p class="flash-message static error"><?= e($this->fatalError) ?></p>
<p>
<a href="<?= Backend::url('renatio/dynamicpdf/templates/index/layouts') ?>"
class="btn btn-default">
<?= e(trans('renatio.dynamicpdf::lang.layouts.return')) ?>
</a>
</p>
<?php endif ?>

View File

@ -0,0 +1,32 @@
<?php Block::put('breadcrumb') ?>
<ul>
<li>
<a href="<?= Backend::url('renatio/dynamicpdf/templates/index/layouts') ?>">
<?= e(trans('renatio.dynamicpdf::lang.layouts.label')) ?>
</a>
</li>
<li><?= e($this->pageTitle) ?></li>
</ul>
<?php Block::endPut() ?>
<?php if (! $this->fatalError) : ?>
<div class="form-preview" style="display: flex; justify-content: center;">
<iframe src="<?= Backend::url('renatio/dynamicpdf/layouts/html/'.$formModel->id) ?>"
style="width: 793px; height: 1121px; border: 1px solid #9098a2;"></iframe>
</div>
<div class="form-buttons">
<a class="btn btn-default"
href="<?= Backend::url('renatio/dynamicpdf/layouts/update/'.$formModel->id) ?>">
<?= e(trans('backend::lang.form.close')) ?>
</a>
</div>
<?php else: ?>
<p class="flash-message static error"><?= e($this->fatalError) ?></p>
<p>
<a href="<?= Backend::url('renatio/dynamicpdf/templates/index/layouts') ?>"
class="btn btn-default">
<?= e(trans('renatio.dynamicpdf::lang.layouts.return')) ?>
</a>
</p>
<?php endif ?>

View File

@ -0,0 +1,20 @@
<?php Block::put('breadcrumb') ?>
<ul>
<li>
<a href="<?= Backend::url('renatio/dynamicpdf/templates/index/layouts') ?>">
<?= e(trans('renatio.dynamicpdf::lang.layouts.label')) ?>
</a>
</li>
<li><?= e($this->pageTitle) ?></li>
</ul>
<?php Block::endPut() ?>
<?php if ($this->fatalError) : ?>
<p class="flash-message static error"><?= e($this->fatalError) ?></p>
<p>
<a href="<?= Backend::url('renatio/dynamicpdf/templates/index/layouts') ?>"
class="btn btn-default">
<?= e(trans('renatio.dynamicpdf::lang.layouts.return')) ?>
</a>
</p>
<?php endif ?>

View File

@ -0,0 +1,86 @@
<?php Block::put('breadcrumb') ?>
<ul>
<li>
<a href="<?= Backend::url('renatio/dynamicpdf/templates/index/layouts') ?>">
<?= e(trans('renatio.dynamicpdf::lang.layouts.label')) ?>
</a>
</li>
<li><?= e($this->pageTitle) ?></li>
</ul>
<?php Block::endPut() ?>
<?php if (! $this->fatalError) : ?>
<?= Form::open(['class' => 'layout']) ?>
<div class="layout-row">
<?= $this->formRender() ?>
</div>
<div class="form-buttons pt-4">
<div class="loading-indicator-container">
<button type="submit"
data-request="onSave"
data-request-data="redirect:0"
data-hotkey="ctrl+s, cmd+s"
data-load-indicator="<?= e(trans('backend::lang.form.saving_name', ['name' => $formRecordName])) ?>"
class="btn btn-primary">
<?= e(trans('backend::lang.form.save')) ?>
</button>
<button type="button"
data-request="onSave"
data-request-data="close:1"
data-hotkey="ctrl+enter, cmd+enter"
data-load-indicator="<?= e(trans('backend::lang.form.saving_name', ['name' => $formRecordName])) ?>"
class="btn btn-default">
<?= e(trans('backend::lang.form.save_and_close')) ?>
</button>
<a class="btn btn-info"
href="<?= Backend::url('renatio/dynamicpdf/layouts/preview/'.$formModel->id) ?>">
<?= e(trans('renatio.dynamicpdf::lang.templates.preview_html')) ?>
</a>
<a class="btn btn-info"
target="_blank"
href="<?= Backend::url('renatio/dynamicpdf/layouts/previewpdf/'.$formModel->id) ?>">
<?= e(trans('renatio.dynamicpdf::lang.templates.preview_pdf')) ?>
</a>
<?php if ($formModel->is_locked): ?>
<button type="button"
class="btn btn-danger pull-right"
data-request="onResetDefault"
data-load-indicator="<?= e(trans('backend::lang.form.resetting')) ?>"
data-request-confirm="<?= e(trans('backend::lang.form.action_confirm')) ?>">
<?= e(trans('backend::lang.form.reset_default')) ?>
</button>
<?php else : ?>
<button type="button"
class="oc-icon-trash-o btn-icon danger pull-right"
data-request="onDelete"
data-load-indicator="<?= e(trans('backend::lang.form.deleting_name',
['name' => $formRecordName])) ?>"
data-request-confirm="<?= e(trans('backend::lang.form.action_confirm')) ?>">
</button>
<?php endif ?>
<span class="btn-text">
<?= e(trans('backend::lang.form.or')) ?>
<a href="<?= Backend::url('renatio/dynamicpdf/templates/index/layouts') ?>">
<?= e(trans('backend::lang.form.cancel')) ?>
</a>
</span>
</div>
</div>
<?= Form::close() ?>
<?php else: ?>
<p class="flash-message static error"><?= e($this->fatalError) ?></p>
<p>
<a href="<?= Backend::url('renatio/dynamicpdf/templates/index/layouts') ?>"
class="btn btn-default">
<?= e(trans('renatio.dynamicpdf::lang.layouts.return')) ?>
</a>
</p>
<?php endif ?>

View File

@ -0,0 +1,6 @@
<div data-control="toolbar">
<a href="<?= Backend::url('renatio/dynamicpdf/layouts/create') ?>"
class="btn btn-primary oc-icon-plus">
<?= e(trans('renatio.dynamicpdf::lang.templates.new_layout')) ?>
</a>
</div>

View File

@ -0,0 +1,6 @@
<div data-control="toolbar">
<a href="<?= Backend::url('renatio/dynamicpdf/templates/create') ?>"
class="btn btn-primary oc-icon-plus">
<?= e(trans('renatio.dynamicpdf::lang.templates.new_template')) ?>
</a>
</div>

View File

@ -0,0 +1,31 @@
# ===================================
# Form Behavior Config
# ===================================
# Record name
name: renatio.dynamicpdf::lang.template.menu_label
# Model Form Field configuration
form: $/renatio/dynamicpdf/models/template/fields.yaml
# Model Class name
modelClass: Renatio\DynamicPDF\Models\Template
# Default redirect location
defaultRedirect: renatio/dynamicpdf/templates
# Create page
create:
title: renatio.dynamicpdf::lang.template.create_template
redirect: renatio/dynamicpdf/templates/update/:id
redirectClose: renatio/dynamicpdf/templates
# Update page
update:
title: renatio.dynamicpdf::lang.template.edit_template
redirect: renatio/dynamicpdf/templates
redirectClose: renatio/dynamicpdf/templates
# Preview page
preview:
title: renatio.dynamicpdf::lang.templates.preview_html

View File

@ -0,0 +1,44 @@
# ===================================
# List Behavior Config
# ===================================
# Model List Column configuration
list: $/renatio/dynamicpdf/models/layout/columns.yaml
# Model Class name
modelClass: Renatio\DynamicPDF\Models\Layout
# List Title
title: renatio.dynamicpdf::lang.layouts.label
# Link URL for each record
recordUrl: renatio/dynamicpdf/layouts/update/:id
# Message to display if the list is empty
noRecordsMessage: backend::lang.list.no_records
# Records to display per page
recordsPerPage: 20
# Displays the list column set up button
showSetup: true
# Displays the sorting link on each column
showSorting: true
# Default sorting column
defaultSort:
column: created_at
direction: desc
# Display checkboxes next to each record
showCheckboxes: false
# Toolbar widget configuration
toolbar:
# Partial for toolbar buttons
buttons: list_layouts_toolbar
# Search widget configuration
search:
prompt: backend::lang.list.search_prompt

View File

@ -0,0 +1,44 @@
# ===================================
# List Behavior Config
# ===================================
# Model List Column configuration
list: $/renatio/dynamicpdf/models/template/columns.yaml
# Model Class name
modelClass: Renatio\DynamicPDF\Models\Template
# List Title
title: renatio.dynamicpdf::lang.templates.label
# Link URL for each record
recordUrl: renatio/dynamicpdf/templates/update/:id
# Message to display if the list is empty
noRecordsMessage: backend::lang.list.no_records
# Records to display per page
recordsPerPage: 20
# Displays the list column set up button
showSetup: true
# Displays the sorting link on each column
showSorting: true
# Default sorting column
defaultSort:
column: created_at
direction: desc
# Display checkboxes next to each record
showCheckboxes: false
# Toolbar widget configuration
toolbar:
# Partial for toolbar buttons
buttons: list_templates_toolbar
# Search widget configuration
search:
prompt: backend::lang.list.search_prompt

View File

@ -0,0 +1,58 @@
<?php Block::put('breadcrumb') ?>
<ul>
<li>
<a href="<?= Backend::url('renatio/dynamicpdf/templates') ?>">
<?= e(trans('renatio.dynamicpdf::lang.templates.label')) ?>
</a>
</li>
<li><?= e($this->pageTitle) ?></li>
</ul>
<?php Block::endPut() ?>
<?php if (! $this->fatalError) : ?>
<?= Form::open(['class' => 'layout']) ?>
<div class="layout-row">
<?= $this->formRender() ?>
</div>
<div class="form-buttons pt-4">
<div class="loading-indicator-container">
<button type="submit"
data-request="onSave"
data-hotkey="ctrl+s, cmd+s"
data-load-indicator="<?= e(trans('backend::lang.form.creating_name',
['name' => $formRecordName])) ?>"
class="btn btn-primary">
<?= e(trans('backend::lang.form.create')) ?>
</button>
<button type="button"
data-request="onSave"
data-request-data="close:1"
data-hotkey="ctrl+enter, cmd+enter"
data-load-indicator="<?= e(trans('backend::lang.form.creating_name',
['name' => $formRecordName])) ?>"
class="btn btn-default">
<?= e(trans('backend::lang.form.create_and_close')) ?>
</button>
<span class="btn-text">
<?= e(trans('backend::lang.form.or')) ?>
<a href="<?= Backend::url('renatio/dynamicpdf/templates') ?>">
<?= e(trans('backend::lang.form.cancel')) ?>
</a>
</span>
</div>
</div>
<?= Form::close() ?>
<?php else: ?>
<p class="flash-message static error"><?= e($this->fatalError) ?></p>
<p>
<a href="<?= Backend::url('renatio/dynamicpdf/templates') ?>"
class="btn btn-default">
<?= e(trans('renatio.dynamicpdf::lang.templates.return')) ?>
</a>
</p>
<?php endif ?>

View File

@ -0,0 +1,25 @@
<div class="control-tabs content-tabs tabs-flush" data-control="tab">
<ul class="nav nav-tabs">
<li class="<?= $activeTab == 'templates' ? 'active' : '' ?>">
<a href="#templates" data-tab-url="<?= Backend::url('renatio/dynamicpdf/templates/index/templates') ?>">
<?= e(trans('renatio.dynamicpdf::lang.templates.templates')) ?>
</a>
</li>
<li class="<?= $activeTab == 'layouts' ? 'active' : '' ?>">
<a href="#layouts" data-tab-url="<?= Backend::url('renatio/dynamicpdf/templates/index/layouts') ?>">
<?= e(trans('renatio.dynamicpdf::lang.templates.layouts')) ?>
</a>
</li>
</ul>
<div class="tab-content">
<div class="tab-pane <?= $activeTab == 'templates' ? 'active' : '' ?>">
<?= $this->listRender('templates') ?>
</div>
<div class="tab-pane <?= $activeTab == 'layouts' ? 'active' : '' ?>">
<?= $this->listRender('layouts') ?>
</div>
</div>
</div>

View File

@ -0,0 +1,32 @@
<?php Block::put('breadcrumb') ?>
<ul>
<li>
<a href="<?= Backend::url('renatio/dynamicpdf/templates') ?>">
<?= e(trans('renatio.dynamicpdf::lang.templates.label')) ?>
</a>
</li>
<li><?= e($this->pageTitle) ?></li>
</ul>
<?php Block::endPut() ?>
<?php if (! $this->fatalError) : ?>
<div class="form-preview" style="display: flex; justify-content: center;">
<iframe src="<?= Backend::url('renatio/dynamicpdf/templates/html/'.$formModel->id) ?>"
style="width: 793px; height: 1121px; border: 1px solid #9098a2;"></iframe>
</div>
<div class="form-buttons">
<a class="btn btn-default"
href="<?= Backend::url('renatio/dynamicpdf/templates/update/'.$formModel->id) ?>">
<?= e(trans('backend::lang.form.close')) ?>
</a>
</div>
<?php else: ?>
<p class="flash-message static error"><?= e($this->fatalError) ?></p>
<p>
<a href="<?= Backend::url('renatio/dynamicpdf/templates') ?>"
class="btn btn-default">
<?= e(trans('renatio.dynamicpdf::lang.templates.return')) ?>
</a>
</p>
<?php endif ?>

View File

@ -0,0 +1,20 @@
<?php Block::put('breadcrumb') ?>
<ul>
<li>
<a href="<?= Backend::url('renatio/dynamicpdf/templates') ?>">
<?= e(trans('renatio.dynamicpdf::lang.templates.label')) ?>
</a>
</li>
<li><?= e($this->pageTitle) ?></li>
</ul>
<?php Block::endPut() ?>
<?php if ($this->fatalError) : ?>
<p class="flash-message static error"><?= e($this->fatalError) ?></p>
<p>
<a href="<?= Backend::url('renatio/dynamicpdf/templates') ?>"
class="btn btn-default">
<?= e(trans('renatio.dynamicpdf::lang.templates.return')) ?>
</a>
</p>
<?php endif ?>

View File

@ -0,0 +1,86 @@
<?php Block::put('breadcrumb') ?>
<ul>
<li>
<a href="<?= Backend::url('renatio/dynamicpdf/templates') ?>">
<?= e(trans('renatio.dynamicpdf::lang.templates.label')) ?>
</a>
</li>
<li><?= e($this->pageTitle) ?></li>
</ul>
<?php Block::endPut() ?>
<?php if (! $this->fatalError) : ?>
<?= Form::open(['class' => 'layout']) ?>
<div class="layout-row">
<?= $this->formRender() ?>
</div>
<div class="form-buttons pt-4">
<div class="loading-indicator-container">
<button type="submit"
data-request="onSave"
data-request-data="redirect:0"
data-hotkey="ctrl+s, cmd+s"
data-load-indicator="<?= e(trans('backend::lang.form.saving_name', ['name' => $formRecordName])) ?>"
class="btn btn-primary">
<?= e(trans('backend::lang.form.save')) ?>
</button>
<button type="button"
data-request="onSave"
data-request-data="close:1"
data-hotkey="ctrl+enter, cmd+enter"
data-load-indicator="<?= e(trans('backend::lang.form.saving_name', ['name' => $formRecordName])) ?>"
class="btn btn-default">
<?= e(trans('backend::lang.form.save_and_close')) ?>
</button>
<a class="btn btn-info"
href="<?= Backend::url('renatio/dynamicpdf/templates/preview/'.$formModel->id) ?>">
<?= e(trans('renatio.dynamicpdf::lang.templates.preview_html')) ?>
</a>
<a class="btn btn-info"
target="_blank"
href="<?= Backend::url('renatio/dynamicpdf/templates/previewpdf/'.$formModel->id) ?>">
<?= e(trans('renatio.dynamicpdf::lang.templates.preview_pdf')) ?>
</a>
<?php if ($formModel->getView()): ?>
<button type="button"
class="btn btn-danger pull-right"
data-request="onResetDefault"
data-load-indicator="<?= e(trans('backend::lang.form.resetting')) ?>"
data-request-confirm="<?= e(trans('backend::lang.form.action_confirm')) ?>">
<?= e(trans('backend::lang.form.reset_default')) ?>
</button>
<?php else : ?>
<button type="button"
class="oc-icon-trash-o btn-icon danger pull-right"
data-request="onDelete"
data-load-indicator="<?= e(trans('backend::lang.form.deleting_name',
['name' => $formRecordName])) ?>"
data-request-confirm="<?= e(trans('backend::lang.form.action_confirm')) ?>">
</button>
<?php endif ?>
<span class="btn-text">
<?= e(trans('backend::lang.form.or')) ?>
<a href="<?= Backend::url('renatio/dynamicpdf/templates') ?>">
<?= e(trans('backend::lang.form.cancel')) ?>
</a>
</span>
</div>
</div>
<?= Form::close() ?>
<?php else: ?>
<p class="flash-message static error"><?= e($this->fatalError) ?></p>
<p>
<a href="<?= Backend::url('renatio/dynamicpdf/templates') ?>"
class="btn btn-default">
<?= e(trans('renatio.dynamicpdf::lang.templates.return')) ?>
</a>
</p>
<?php endif ?>

Binary file not shown.

After

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 99 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 119 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 227 KiB

View File

@ -0,0 +1,54 @@
<?php
return [
'plugin' => [
'name' => 'Dynamické PDF',
'description' => 'Generování dynamických a upravitelných PDF.',
],
'templates' => [
'label' => 'PDF Šablony',
'code' => 'Kód',
'title' => 'Nadpis',
'description' => 'Popis',
'layout' => 'Layout',
'empty_option' => '-- Bez šablony --',
'code_comment' => 'Unikátní kód patřící pouze této šabloně',
'content_html' => 'HTML',
'content_css' => 'CSS',
'name' => 'Jméno',
'return' => 'Zpět na seznam šablon',
'new_template' => 'Nová šablona',
'new_layout' => 'Nový layout',
'templates' => 'Šablony',
'layouts' => 'Layouty',
'background_img' => 'Obrázek pozadí',
'preview_pdf' => 'Náhled',
'created_at' => 'Vytvořeno v',
'updated_at' => 'Upraveno v',
'background_img_comment' => 'Pro správné zobrazení použijte obrázek s 96 DPI'
],
'template' => [
'menu_label' => 'PDF Šablony',
'create_template' => 'Vytvoření PDF šablony',
'edit_template' => 'Úprava PDF šablony',
],
'layouts' => [
'label' => 'PDF Layouty',
'return' => 'Zpět na seznam PDF layoutů',
],
'layout' => [
'menu_label' => 'PDF Layouty',
'create_layout' => 'Vytvoření PDF layoutu',
'edit_layout' => 'Úprava PDF layoutu',
],
'settings' => [
'description' => 'Správa PDF šablon a layoutů.',
],
'permissions' => [
'label' => 'Správa PDF šablon',
'tab' => 'PDF',
],
'menu' => [
'label' => 'PDF'
]
];

View File

@ -0,0 +1,56 @@
<?php
return [
'plugin' => [
'name' => 'DynamicPDF',
'description' => 'Generiert dynamische und anpassbare PDFs.',
],
'templates' => [
'label' => 'Vorlagen',
'code' => 'Code',
'title' => 'Titel',
'description' => 'Beschreibung',
'layout' => 'Layout',
'empty_option' => '-- Kein Layout --',
'code_comment' => 'Code wird verwendet um die Vorlage eindeutig zu Identifizieren.',
'content_html' => 'HTML',
'content_css' => 'CSS',
'name' => 'Name',
'return' => 'Zurück zu den PDF Vorlagen',
'new_template' => 'Neue Vorlage',
'new_layout' => 'Neues Layout',
'templates' => 'Vorlagen',
'layouts' => 'Layouts',
'background_img' => 'Hintergrundbild',
'preview_html' => 'HTML Vorschau',
'preview_pdf' => 'PDF Vorschau',
'created_at' => 'Erstellt am',
'updated_at' => 'Aktualisiert am',
'background_img_comment' => 'Bilder mit 96 DPI eignen sich am Besten',
],
'template' => [
'menu_label' => 'Vorlagen',
'create_template' => 'Erstelle Vorlage',
'edit_template' => 'Bearbeite Vorlage',
],
'layouts' => [
'label' => 'Layouts',
'return' => 'Zurük zu den Layouts',
],
'layout' => [
'menu_label' => 'Layout',
'create_layout' => 'Erstelle Layout',
'edit_layout' => 'Bearbeite Layout',
],
'settings' => [
'description' => 'Verwaltung von Vorlagen und Layouts.',
],
'permissions' => [
'manage_templates' => 'Verwalte Vorlagen',
'manage_layouts' => 'Verwalte Layouts',
'tab' => 'PDF',
],
'menu' => [
'label' => 'PDF',
],
];

View File

@ -0,0 +1,76 @@
<?php
return [
'plugin' => [
'name' => 'DynamicPDF',
'description' => 'Generate dynamic and customized PDFs.',
],
'templates' => [
'label' => 'Templates',
'code' => 'Code',
'title' => 'Title',
'description' => 'Description',
'layout' => 'Layout',
'empty_option' => '-- No layout --',
'code_comment' => 'Unique code used to refer to this template',
'content_html' => 'HTML',
'content_css' => 'CSS/LESS',
'name' => 'Name',
'return' => 'Return to templates list',
'new_template' => 'New Template',
'new_layout' => 'New Layout',
'templates' => 'Templates',
'layouts' => 'Layouts',
'background_img' => 'Background Image',
'preview_html' => 'Preview HTML',
'preview_pdf' => 'Preview PDF',
'created_at' => 'Created at',
'updated_at' => 'Updated at',
'background_img_comment' => 'Use image with at least 96 DPI for correct display. Recommended 300 DPI.',
'size' => 'Paper size',
'orientation' => 'Paper orientation',
],
'template' => [
'menu_label' => 'Template',
'create_template' => 'Create Template',
'edit_template' => 'Edit Template',
'not_found' => 'Unable to find a registered template with code',
],
'layouts' => [
'label' => 'Layouts',
'return' => 'Return to layouts list',
],
'layout' => [
'menu_label' => 'Layout',
'create_layout' => 'Create Layout',
'edit_layout' => 'Edit Layout',
'not_found' => 'Unable to find a registered layout with code',
],
'settings' => [
'description' => 'Manage templates and layouts.',
],
'permissions' => [
'manage_templates' => 'Manage templates',
'manage_layouts' => 'Manage layouts',
'tab' => 'PDF',
],
'menu' => [
'label' => 'PDF Templates',
'category' => 'PDF',
'description' => 'Modify the PDF templates and manage PDF layouts.',
],
'orientation' => [
'portrait' => 'Portrait',
'landscape' => 'Landscape',
],
'options' => [
'empty' => '-- choose --',
],
'tab' => [
'options' => 'Options',
],
'demo' => [
'enabled' => 'Demo is enabled. Please refresh PDF templates list.',
'disabled' => 'Demo is disabled. Please refresh PDF templates list.',
],
];

View File

@ -0,0 +1,54 @@
<?php
return [
'plugin' => [
'name' => 'DynamicPDF',
'description' => 'Genera PDF dinámicos y personalizados.',
],
'templates' => [
'label' => 'Plantillas PDF',
'code' => 'Código',
'title' => 'Título',
'description' => 'Descripción',
'layout' => 'Diseño',
'empty_option' => '-- Ningúno --',
'code_comment' => 'Código único para hacer referencia a esta plantilla',
'content_html' => 'HTML',
'content_css' => 'CSS',
'name' => 'Nombre',
'return' => 'Volver a la lista de plantillas PDF',
'new_template' => 'Nueva Plantilla',
'new_layout' => 'Nuevo Diseño',
'templates' => 'Plantillas',
'layouts' => 'Diseños',
'background_img' => 'Imagen de fondo',
'preview_pdf' => 'Previsualizar',
'created_at' => 'Creado en',
'updated_at' => 'Modificado en',
'background_img_comment' => 'Utilize una imagen de 96 DPI para una correcta visualización'
],
'template' => [
'menu_label' => 'Plantilla PDF',
'create_template' => 'Crear Plantilla PDF',
'edit_template' => 'Editar Plantilla PDF',
],
'layouts' => [
'label' => 'Diseños PDF',
'return' => 'Volver la la lista de diseños PDF',
],
'layout' => [
'menu_label' => 'Diseño PDF',
'create_layout' => 'Crear Diseño PDF',
'edit_layout' => 'Editar Diseño PDF',
],
'settings' => [
'description' => 'Administrar plantillas y diseños PDF.',
],
'permissions' => [
'label' => 'Administrar plantillas PDF',
'tab' => 'PDF',
],
'menu' => [
'label' => 'PDF'
]
];

View File

@ -0,0 +1,54 @@
<?php
return [
'plugin' => [
'name' => 'DynamicPDF',
'description' => 'Genera PDF dinámicos y personalizados.',
],
'templates' => [
'label' => 'Plantillas PDF',
'code' => 'Código',
'title' => 'Título',
'description' => 'Descripción',
'layout' => 'Diseño',
'empty_option' => '-- Ningúno --',
'code_comment' => 'Código único para hacer referencia a esta plantilla',
'content_html' => 'HTML',
'content_css' => 'CSS',
'name' => 'Nombre',
'return' => 'Volver a la lista de plantillas PDF',
'new_template' => 'Nueva Plantilla',
'new_layout' => 'Nuevo Diseño',
'templates' => 'Plantillas',
'layouts' => 'Diseños',
'background_img' => 'Imagen de fondo',
'preview_pdf' => 'Previsualizar',
'created_at' => 'Creado en',
'updated_at' => 'Modificado en',
'background_img_comment' => 'Utilize una imagen de 96 DPI para una correcta visualización'
],
'template' => [
'menu_label' => 'Plantilla PDF',
'create_template' => 'Crear Plantilla PDF',
'edit_template' => 'Editar Plantilla PDF',
],
'layouts' => [
'label' => 'Diseños PDF',
'return' => 'Volver la la lista de diseños PDF',
],
'layout' => [
'menu_label' => 'Diseño PDF',
'create_layout' => 'Crear Diseño PDF',
'edit_layout' => 'Editar Diseño PDF',
],
'settings' => [
'description' => 'Administrar plantillas y diseños PDF.',
],
'permissions' => [
'label' => 'Administrar plantillas PDF',
'tab' => 'PDF',
],
'menu' => [
'label' => 'PDF'
]
];

View File

@ -0,0 +1,65 @@
<?php
return [
'plugin' => [
'name' => 'Dinamikus PDF',
'description' => 'Egyedi PDF fájlok generálása.',
],
'templates' => [
'label' => 'Sablonok',
'code' => 'Kód',
'title' => 'Cím',
'description' => 'Leírás',
'layout' => 'Elrendezés',
'empty_option' => '-- nincs --',
'code_comment' => 'Egyedi kódot adjon meg.',
'content_html' => 'HTML',
'content_css' => 'CSS',
'name' => 'Név',
'return' => 'Vissza a sablonokhoz',
'new_template' => 'Új sablon',
'new_layout' => 'Új elrendezés',
'templates' => 'Sablonok',
'layouts' => 'Elrendezések',
'background_img' => 'Háttérkép',
'preview_html' => 'HTML előnézet',
'preview_pdf' => 'PDF előnézet',
'created_at' => 'Létrehozva',
'updated_at' => 'Módosítva',
'background_img_comment' => 'A megfelelő megjelenéshez 96 DPI méretű képet használjon.',
'size' => 'Papír mérete',
'orientation' => 'Papír tájolása',
],
'template' => [
'menu_label' => 'Sablon',
'create_template' => 'Sablon létrehozása',
'edit_template' => 'Sablon szerkesztése',
],
'layouts' => [
'label' => 'Elrendezések',
'return' => 'Vissza az elrendezésekhez',
],
'layout' => [
'menu_label' => 'Elrendezés',
'create_layout' => 'Elrendezés létrehozása',
'edit_layout' => 'Elrendezés szerkesztése',
],
'settings' => [
'description' => 'Sablonok és elrendezések kezelése.',
],
'permissions' => [
'manage_templates' => 'Sablonok kezelése',
'manage_layouts' => 'Elrendezések kezelése',
'tab' => 'PDF',
],
'menu' => [
'label' => 'PDF'
],
'orientation' => [
'portrait' => 'Álló',
'landscape' => 'Fekvő',
],
'options' => [
'empty' => '-- válasszon --',
],
];

View File

@ -0,0 +1,70 @@
<?php
return [
'plugin' => [
'name' => 'DynamicPDF',
'description' => 'Generuj dynamiczne pliki PDF.',
],
'templates' => [
'label' => 'Szablony',
'code' => 'Kod',
'title' => 'Tytuł',
'description' => 'Opis',
'layout' => 'Układ',
'empty_option' => '-- Brak układu --',
'code_comment' => 'Unikalny kod powiązany z tym szablonem',
'content_html' => 'HTML',
'content_css' => 'CSS/LESS',
'name' => 'Nazwa',
'return' => 'Powrót do listy szablonów',
'new_template' => 'Nowy szablon',
'new_layout' => 'Nowy układ',
'templates' => 'Szablony',
'layouts' => 'Układy',
'background_img' => 'Obraz w tle',
'preview_html' => 'Podgląd HTML',
'preview_pdf' => 'Podgląd PDF',
'created_at' => 'Data utworzenia',
'updated_at' => 'Data edycji',
'background_img_comment' => 'Użyj obrazu o rozdzielczości przynajmniej 96 DPI do poprawnego wyświetlenia. Zalecany obraz 300 DPI.',
'size' => 'Rozmiar papieru',
'orientation' => 'Orientacja papieru',
],
'template' => [
'menu_label' => 'Szablon',
'create_template' => 'Utwórz szablon',
'edit_template' => 'Edycja szablonu',
],
'layouts' => [
'label' => 'Układu',
'return' => 'Powrót do listy układów',
],
'layout' => [
'menu_label' => 'Układ',
'create_layout' => 'Utwórz układ',
'edit_layout' => 'Edycja układu',
],
'settings' => [
'description' => 'Zarządzaj szablonami i układami.',
],
'permissions' => [
'manage_templates' => 'Zarządzaj szablonami',
'manage_layouts' => 'Zarządzaj układami',
'tab' => 'PDF',
],
'menu' => [
'label' => 'Szablony PDF',
'category' => 'PDF',
'description' => 'Modyfikuj szablony i układy PDF.',
],
'orientation' => [
'portrait' => 'Pionowy',
'landscape' => 'Poziomy',
],
'options' => [
'empty' => '-- wybierz --',
],
'tab' => [
'options' => 'Opcje',
],
];

View File

@ -0,0 +1,76 @@
<?php
return [
'plugin' => [
'name' => 'DynamicPDF',
'description' => 'Gere PDFs dinâmicos e personalizados.',
],
'templates' => [
'label' => 'Modelos',
'code' => 'Código',
'title' => 'Título',
'description' => 'Descrição',
'layout' => 'Modelo',
'empty_option' => '-- Sem modelo --',
'code_comment' => 'Código exclusivo usado para se referir a este modelo',
'content_html' => 'HTML',
'content_css' => 'CSS/LESS',
'name' => 'Nome',
'return' => 'Voltar à lista de modelos',
'new_template' => 'Novo modelo',
'new_layout' => 'Novo Layout',
'templates' => 'Modelos',
'layouts' => 'Layouts',
'background_img' => 'Imagem de fundo',
'preview_html' => 'Pré-visualizar HTML',
'preview_pdf' => 'Pré-visualizar PDF',
'created_at' => 'Criado em',
'updated_at' => 'Atualizado em',
'background_img_comment' => 'Use imagem com pelo menos 96 DPI para exibição correta. Recomendado 300 de DPI.',
'size' => 'Tamanho do papel',
'orientation' => 'Orientação do papel',
],
'template' => [
'menu_label' => 'Modelo',
'create_template' => 'Criar Modelo',
'edit_template' => 'Editar Modelo',
'not_found' => 'Incapaz de encontrar um modelo registrado com código',
],
'layouts' => [
'label' => 'Layouts',
'return' => 'Voltar à lista de layouts',
],
'layout' => [
'menu_label' => 'Layout',
'create_layout' => 'Criar Layout',
'edit_layout' => 'Editar Layout',
'not_found' => 'Incapaz de encontrar um layout registrado com código',
],
'settings' => [
'description' => 'Gerencie modelos e layouts.',
],
'permissions' => [
'manage_templates' => 'Gerencie modelos',
'manage_layouts' => 'Gerencie layouts',
'tab' => 'PDF',
],
'menu' => [
'label' => 'Modelos PDF',
'category' => 'PDF',
'description' => 'Modifique os modelos de PDF e gerencie layouts de PDF.',
],
'orientation' => [
'portrait' => 'Retrato',
'landscape' => 'Paisagem',
],
'options' => [
'empty' => '-- escolha --',
],
'tab' => [
'options' => 'Opções',
],
'demo' => [
'enabled' => 'A demonstração está ativada. Atualize a lista de modelos de PDF.',
'disabled' => 'A demonstração está desativada. Atualize a lista de modelos de PDF.',
],
];

View File

@ -0,0 +1,69 @@
<?php
namespace Renatio\DynamicPDF\Models;
use Less_Parser;
use October\Rain\Database\Model;
use October\Rain\Database\Traits\Validation;
use October\Rain\Exception\ApplicationException;
use Renatio\DynamicPDF\Classes\PDF;
use Renatio\DynamicPDF\Classes\PDFManager;
use Renatio\DynamicPDF\Classes\PDFParser;
use System\Models\File;
class Layout extends Model
{
use Validation;
public $table = 'renatio_dynamicpdf_pdf_layouts';
public $rules = [
'name' => ['required'],
'code' => ['required', 'unique:renatio_dynamicpdf_pdf_layouts'],
'content_html' => ['required'],
];
public $attachOne = [
'background_img' => File::class,
];
public function getHtmlAttribute()
{
return PDF::loadLayout($this->code)->getDompdf()->output_html();
}
public static function byCode($code)
{
return static::whereCode($code)->firstOrFail();
}
public function getCSS()
{
$parser = new Less_Parser;
return $parser->parse($this->content_css)->getCss();
}
public function fillFromCode()
{
if (! ($path = $this->getView())) {
throw new ApplicationException(e(trans('renatio.dynamicpdf::lang.layout.not_found')).': '.$this->code);
}
$this->fillFromView($path);
}
public function fillFromView($path)
{
$sections = PDFParser::sections($path);
$this->name = array_get($sections, 'settings.name', '???');
$this->content_css = array_get($sections, 'css');
$this->content_html = array_get($sections, 'html');
}
public function getView()
{
return array_get(PDFManager::instance()->listRegisteredLayouts(), $this->code);
}
}

View File

@ -0,0 +1,87 @@
<?php
namespace Renatio\DynamicPDF\Models;
use Dompdf\Adapter\CPDF;
use October\Rain\Database\Model;
use October\Rain\Database\Traits\Validation;
use October\Rain\Exception\ApplicationException;
use Renatio\DynamicPDF\Classes\PDF;
use Renatio\DynamicPDF\Classes\PDFManager;
use Renatio\DynamicPDF\Classes\PDFParser;
class Template extends Model
{
use Validation;
public $table = 'renatio_dynamicpdf_pdf_templates';
public $belongsTo = [
'layout' => Layout::class,
];
public $rules = [
'title' => ['required'],
'code' => ['required', 'unique:renatio_dynamicpdf_pdf_templates'],
'content_html' => ['required'],
];
public function afterFetch()
{
if (! $this->is_custom) {
$this->fillFromView($this->code);
}
}
public function fillFromCode()
{
if (! ($path = $this->getView())) {
throw new ApplicationException(e(trans('renatio.dynamicpdf::lang.template.not_found')).': '.$this->code);
}
$this->fillFromView($path);
}
public function fillFromView($path)
{
$sections = PDFParser::sections($path);
$this->title = array_get($sections, 'settings.title', '???');
$this->code = $path;
$this->layout = Layout::whereCode(array_get($sections, 'settings.layout'))->first();
$this->size = array_get($sections, 'settings.size');
$this->orientation = array_get($sections, 'settings.orientation');
$this->description = array_get($sections, 'settings.description');
$this->content_html = array_get($sections, 'html');
}
public function getHtmlAttribute()
{
return PDF::loadTemplate($this->code)->getDompdf()->output_html();
}
public static function byCode($code)
{
return static::whereCode($code)->firstOrFail();
}
public static function getSizeOptions()
{
$sizes = array_keys(CPDF::$PAPER_SIZES);
return array_combine($sizes, $sizes);
}
public static function getOrientationOptions()
{
return [
'portrait' => 'renatio.dynamicpdf::lang.orientation.portrait',
'landscape' => 'renatio.dynamicpdf::lang.orientation.landscape',
];
}
public function getView()
{
return array_get(PDFManager::instance()->listRegisteredTemplates(), $this->code);
}
}

View File

@ -0,0 +1,21 @@
# ===================================
# Column Definitions
# ===================================
columns:
name:
label: renatio.dynamicpdf::lang.templates.name
searchable: true
code:
label: renatio.dynamicpdf::lang.templates.code
searchable: true
created_at:
label: renatio.dynamicpdf::lang.templates.created_at
type: datetime
updated_at:
label: renatio.dynamicpdf::lang.templates.updated_at
type: datetime

View File

@ -0,0 +1,60 @@
# ===================================
# Field Definitions
# ===================================
fields:
name@create:
label: renatio.dynamicpdf::lang.templates.name
span: left
name@update:
label: renatio.dynamicpdf::lang.templates.name
span: full
code@create:
label: renatio.dynamicpdf::lang.templates.code
comment: renatio.dynamicpdf::lang.templates.code_comment
preset: name
span: right
secondaryTabs:
fields:
content_html:
type: codeeditor
size: giant
tab: renatio.dynamicpdf::lang.templates.content_html
language: html
stretch: true
default: |
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title>Document</title>
<style type="text/css" media="screen">
{{ css|raw }}
</style>
</head>
<body>
{{ content_html|raw }}
</body>
</html>
content_css:
tab: renatio.dynamicpdf::lang.templates.content_css
type: codeeditor
size: giant
language: css
stretch: true
background_img:
label: renatio.dynamicpdf::lang.templates.background_img
tab: renatio.dynamicpdf::lang.tab.options
type: fileupload
mode: image
comment: renatio.dynamicpdf::lang.templates.background_img_comment
attachOnUpload: true
span: left

View File

@ -0,0 +1,30 @@
# ===================================
# Column Definitions
# ===================================
columns:
title:
label: renatio.dynamicpdf::lang.templates.name
searchable: true
code:
label: renatio.dynamicpdf::lang.templates.code
searchable: true
description:
label: renatio.dynamicpdf::lang.templates.description
searchable: true
layout:
label: renatio.dynamicpdf::lang.templates.layout
relation: layout
select: name
created_at:
label: renatio.dynamicpdf::lang.templates.created_at
type: datetime
updated_at:
label: renatio.dynamicpdf::lang.templates.updated_at
type: datetime

View File

@ -0,0 +1,52 @@
# ===================================
# Field Definitions
# ===================================
fields:
title:
label: renatio.dynamicpdf::lang.templates.title
span: left
code@create:
label: renatio.dynamicpdf::lang.templates.code
comment: renatio.dynamicpdf::lang.templates.code_comment
preset: title
span: right
layout:
label: renatio.dynamicpdf::lang.templates.layout
type: relation
emptyOption: renatio.dynamicpdf::lang.templates.empty_option
span: auto
description:
label: renatio.dynamicpdf::lang.templates.description
tab: renatio.dynamicpdf::lang.tab.options
type: textarea
size: tiny
secondaryTabs:
fields:
content_html:
type: codeeditor
size: giant
tab: renatio.dynamicpdf::lang.templates.content_html
language: html
stretch: true
size:
label: renatio.dynamicpdf::lang.templates.size
tab: renatio.dynamicpdf::lang.tab.options
type: dropdown
emptyOption: renatio.dynamicpdf::lang.options.empty
span: left
orientation:
label: renatio.dynamicpdf::lang.templates.orientation
tab: renatio.dynamicpdf::lang.tab.options
type: dropdown
emptyOption: renatio.dynamicpdf::lang.options.empty
span: right

View File

@ -0,0 +1,24 @@
<?php
namespace Renatio\DynamicPDF\Updates;
use October\Rain\Database\Schema\Blueprint;
use October\Rain\Database\Updates\Migration;
use Schema;
class AddIsCustomToTemplatesTable extends Migration
{
public function up()
{
Schema::table('renatio_dynamicpdf_pdf_templates', function (Blueprint $table) {
$table->boolean('is_custom')->default(false);
});
}
public function down()
{
Schema::table('renatio_dynamicpdf_pdf_templates', function (Blueprint $table) {
$table->dropColumn('is_custom');
});
}
}

View File

@ -0,0 +1,24 @@
<?php
namespace Renatio\DynamicPDF\Updates;
use October\Rain\Database\Schema\Blueprint;
use October\Rain\Database\Updates\Migration;
use Schema;
class AddIsLockedToLayoutsTable extends Migration
{
public function up()
{
Schema::table('renatio_dynamicpdf_pdf_layouts', function (Blueprint $table) {
$table->boolean('is_locked')->default(false);
});
}
public function down()
{
Schema::table('renatio_dynamicpdf_pdf_layouts', function (Blueprint $table) {
$table->dropColumn('is_locked');
});
}
}

View File

@ -0,0 +1,25 @@
<?php
namespace Renatio\DynamicPDF\Updates;
use October\Rain\Database\Schema\Blueprint;
use October\Rain\Database\Updates\Migration;
use Schema;
class AddPaperConfigurationToTemplatesTable extends Migration
{
public function up()
{
Schema::table('renatio_dynamicpdf_pdf_templates', function (Blueprint $table) {
$table->string('size')->nullable();
$table->string('orientation')->nullable();
});
}
public function down()
{
Schema::table('renatio_dynamicpdf_pdf_templates', function (Blueprint $table) {
$table->dropColumn(['size', 'orientation']);
});
}
}

View File

@ -0,0 +1,27 @@
<?php
namespace Renatio\DynamicPDF\Updates;
use October\Rain\Database\Schema\Blueprint;
use October\Rain\Database\Updates\Migration;
use Schema;
class CreateLayoutsTable extends Migration
{
public function up()
{
Schema::create('renatio_dynamicpdf_pdf_layouts', function (Blueprint $table) {
$table->increments('id');
$table->string('code')->index();
$table->string('name');
$table->text('content_html')->nullable();
$table->text('content_css')->nullable();
$table->timestamps();
});
}
public function down()
{
Schema::dropIfExists('renatio_dynamicpdf_pdf_layouts');
}
}

View File

@ -0,0 +1,28 @@
<?php
namespace Renatio\DynamicPDF\Updates;
use October\Rain\Database\Schema\Blueprint;
use October\Rain\Database\Updates\Migration;
use Schema;
class CreateTemplatesTable extends Migration
{
public function up()
{
Schema::create('renatio_dynamicpdf_pdf_templates', function (Blueprint $table) {
$table->increments('id');
$table->unsignedInteger('layout_id')->index()->nullable();
$table->string('code')->index();
$table->string('title');
$table->text('description')->nullable();
$table->text('content_html')->nullable();
$table->timestamps();
});
}
public function down()
{
Schema::dropIfExists('renatio_dynamicpdf_pdf_templates');
}
}

View File

@ -0,0 +1,20 @@
<?php
namespace Renatio\DynamicPDF\Updates;
use Illuminate\Support\Facades\DB;
use October\Rain\Database\Updates\Migration;
class FixCustomTemplatesError extends Migration
{
public function up()
{
DB::table('renatio_dynamicpdf_pdf_templates')
->update(['is_custom' => 1]);
}
public function down()
{
//
}
}

View File

@ -0,0 +1,48 @@
1.0.1:
- Initialize plugin.
- create_pdf_layouts_table.php
- create_pdf_templates_table.php
1.0.2: Minor changes.
1.1.0: Important update.
1.1.1: Use Twig::parse() facade. Only update for October build 300 and above.
1.1.2: Minor changes.
1.1.3: Add stream parameters and Czech locale. Thanks to @vojtasvoboda.
1.1.4: Add Spanish and Spanish-Argentina locale. Thanks to @kocholes.
1.1.5: UI improvements. Thanks to @kocholes.
2.0.0: This is an important update that contains breaking changes.
2.0.1: Add preview HTML buttons.
2.1.0: This is an important update that contains breaking changes.
2.1.1: Upgrade to DOMPDF 0.7.
2.1.2: Database maintenance. Updated all timestamp columns to be nullable.
2.1.3: Upgrade to DOMPDF 0.8.
2.1.4: German language. Thanks to @TimFoerster.
2.1.5: Fix open_basedir restriction on some hostings. Set isRemoteEnabled flag to allow absolute paths.
2.1.6: Allow Laravel 5.5.
3.0.0: Add support for Laravel 5.5.
3.0.1: Add support for RainLab.Translate plugin.
3.0.2: Fix creating fonts directory.
3.0.3: Allow to use CMS partials and filters.
3.0.4:
- Add paper size and orientation configuration.
- add_paper_configuration_to_templates_table.php
3.0.5: Support LESS in PDF layouts.
4.0.0: Require PHP 7.1. Please see upgrade guide before update.
4.0.1: Fix error when active theme is not set.
4.0.2:
- Allow to register mail templates and layouts.
- add_is_custom_to_templates_table.php
- add_is_locked_to_layouts_table.php
4.0.3:
- Fix custom templates error.
- fix_custom_templates_error.php
4.0.4: Fix composer installation.
4.0.5: Fix custom template error.
4.0.6: Allow to reset view template to default.
4.0.7: Add Polish translation.
4.0.8: Allow to set dompdf option with dynamic method.
5.0.1: Support October v2.0 and upgrade to DOMPDF 1.0.
5.0.2: Add demo console command.
5.0.3: Update documentation.
5.0.4: Fix preview pdf layout.
5.0.5: Brazilian portuguese language. Thanks to @gcairesdev.
6.0.0: Require October CMS 3.0.

View File

@ -0,0 +1,35 @@
title = "Header and Footer"
description = "Example use of header & footer, page break, page numbers and full background image"
layout = "renatio.dynamicpdf::pdf.layouts.header_and_footer"
==
<div class="px-12 pb-20 text-gray-800">
<h2 class="text-2xl font-bold leading-none">Example Header</h2>
<p class="leading-none mb-4">Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.</p>
<p class="leading-none mb-4">Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.</p>
<p class="leading-none mb-4">Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.</p>
<p class="leading-none mb-4">Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.</p>
<p class="leading-none mb-4">Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.</p>
<p class="leading-none mb-4">Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.</p>
<h4 class="text-2xl font-bold text-center uppercase">Page break here!!!</h4>
<hr class="border-gray-800 border-2">
<div class="page-break"></div>
<h2 class="text-2xl font-bold leading-none">Example Header</h2>
<p class="leading-none mb-4">Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.</p>
<p class="leading-none mb-4">Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.</p>
<p class="leading-none mb-4">Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.</p>
<p class="leading-none mb-4">Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.</p>
</div>

View File

@ -0,0 +1,104 @@
title = "Invoice"
description = "Example invoice with custom font and image embed"
layout = "renatio.dynamicpdf::pdf.layouts.default"
==
<div class="text-sm text-gray-700 leading-none">
<h2 class="text-3xl font-bold leading-none">TablePlus</h2>
<p class="text-gray-400">via Paddle.com</p>
<div class="my-8">
<h1 class="text-4xl font-bold leading-none">Invoice</h1>
</div>
<div class="float-left w-1/2">
<h4 class="mb-4 text-lg font-bold leading-none">Invoice to</h4>
<p class="mb-2 font-bold">John Doe</p>
<p class="mb-2">
Example street 16<br>
Warszawa, 50-100<br>
Poland
</p>
<p>VAT Number: PL2332213309</p>
</div>
<div class="float-right w-1/2 text-right">
<h4 class="mb-4 text-lg font-bold leading-none">Invoice from</h4>
<p class="mb-2 font-bold">Paddle.com Market Ltd</p>
<p class="mb-2">
Judd House 18-29 Mora Street<br>
London, EC1V 8BT<br>
United Kingdom
</p>
<p class="mb-2">VAT Number: EU372017215</p>
<p>Company Number: 08172165</p>
</div>
<div class="clear-both"></div>
<h4 class="mt-8 mb-4 text-lg font-bold leading-none">Your order</h4>
<div class="float-left w-1/2">
<p>Customer: <span class="font-bold">michal.plodowski@gmail.com</span></p>
<p>Order Number / Invoice: <span class="font-bold">#28542217</span></p>
<p>Billing date: <span class="font-bold">01 Sep 2020</span></p>
</div>
<div class="float-right text-right">
<p>Payment method: <span class="font-bold">Visa card ending 2222</span></p>
<p>Currency: <span class="font-bold">USD</span></p>
</div>
<div class="clear-both"></div>
<table class="mt-8 w-full">
<thead>
<tr class="border-b border-solid border-gray-700">
<th class="text-left font-normal border-b border-solid border-gray-700 pb-1">Product</th>
<th class="text-left font-normal border-b border-solid border-gray-700 pb-1">Quantity</th>
<th class="text-right font-normal border-b border-solid border-gray-700 pb-1">Price</th>
</tr>
</thead>
<tbody>
<tr>
<td class="font-bold border-b border-solid border-gray-700 py-4">TablePlus License Renewal</td>
<td class="border-b border-solid border-gray-700 py-4">1</td>
<td class="text-right border-b border-solid border-gray-700 py-4">US$39.00</td>
</tr>
<tr>
<td class="py-2">VAT (0%)</td>
<td colspan="2" class="text-right py-2">US$0.00</td>
</tr>
<tr>
<td class="font-bold">YOUR ORDER</td>
<td colspan="2" class="text-right font-bold text-xl leading-none">US$39.00</td>
</tr>
<tr>
<td colspan="3" class="text-right border-b border-solid border-gray-700 pb-4">
No VAT - Supply may be subject to reverse charge in the country of receipt
</td>
</tr>
</tbody>
</table>
<p class="mt-8 text-center">
The US$39.00 payment will appear on your bank/card statement as:
PADDLE.NET* TABLEPLUS
</p>
<p class="mt-4 text-center">
If you have a problem with your order (e.g. dont recognise the charge, suspect a fraudulent transaction), please visit paddle.net.
</p>
<p class="text-center mt-8"><img class="w-16" src="{{ 'plugins/renatio/dynamicpdf/assets/img/october.png'|app }}"></p>
</div>

View File

@ -0,0 +1,47 @@
name = "Default Layout"
==
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title>Default</title>
<link href="{{ 'plugins/renatio/dynamicpdf/assets/css/tailwind.css'|app }}" rel="stylesheet">
<style>
@font-face {
font-family: 'Open Sans';
src: url({{ 'plugins/renatio/dynamicpdf/assets/fonts/OpenSans-Regular.ttf'|app }});
}
@font-face {
font-family: 'Open Sans';
font-weight: bold;
src: url({{ 'plugins/renatio/dynamicpdf/assets/fonts/OpenSans-Bold.ttf'|app }});
}
@font-face {
font-family: 'Open Sans';
font-style: italic;
src: url({{ 'plugins/renatio/dynamicpdf/assets/fonts/OpenSans-Italic.ttf'|app }});
}
@font-face {
font-family: 'Open Sans';
font-style: italic;
font-weight: bold;
src: url({{ 'plugins/renatio/dynamicpdf/assets/fonts/OpenSans-BoldItalic.ttf'|app }});
}
@page {
margin: 0;
padding: 0;
}
body {
font-family: "Open Sans", sans-serif;
}
</style>
</head>
<body class="p-16">
{{ content_html|raw }}
</body>
</html>

View File

@ -0,0 +1,86 @@
name = "Header and Footer"
==
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title>Header and Footer</title>
<link href="{{ 'plugins/renatio/dynamicpdf/assets/css/tailwind.css'|app }}" rel="stylesheet">
<style>
@font-face {
font-family: 'Open Sans';
src: url({{ 'plugins/renatio/dynamicpdf/assets/fonts/OpenSans-Regular.ttf'|app }});
}
@font-face {
font-family: 'Open Sans';
font-weight: bold;
src: url({{ 'plugins/renatio/dynamicpdf/assets/fonts/OpenSans-Bold.ttf'|app }});
}
@font-face {
font-family: 'Open Sans';
font-style: italic;
src: url({{ 'plugins/renatio/dynamicpdf/assets/fonts/OpenSans-Italic.ttf'|app }});
}
@font-face {
font-family: 'Open Sans';
font-style: italic;
font-weight: bold;
src: url({{ 'plugins/renatio/dynamicpdf/assets/fonts/OpenSans-BoldItalic.ttf'|app }});
}
@page {
margin: 0;
padding: 0;
}
.page-break {
page-break-before: always;
}
body {
font-family: "Open Sans", sans-serif;
}
</style>
</head>
<body style="background-image: url({{ 'plugins/renatio/dynamicpdf/assets/img/bg.jpg'|app }});"
class="bg-left-top bg-no-repeat pt-36">
<script type="text/php">
if (isset($pdf)) {
$size = 9;
$color = [0,0,0];
$font = $fontMetrics->getFont('Open Sans');
$textHeight = $fontMetrics->getFontHeight($font, $size);
$width = $fontMetrics->getTextWidth('Page 1 of 2', $font, $size);
$foot = $pdf->open_object();
$w = $pdf->get_width();
$h = $pdf->get_height();
$y = $h - $textHeight - 13;
$pdf->close_object();
$pdf->add_object($foot, 'all');
$text = "Page {PAGE_NUM} of {PAGE_COUNT}";
// Center the text
$pdf->page_text($w / 2 - $width / 2, $y, $text, $font, $size, $color);
}
</script>
<div class="h-32 fixed top-0 px-12 mt-20 w-full text-gray-500">
This is example header text
</div>
<div class="h-24 fixed bottom-0 px-12 w-full text-gray-500">
This is example footer text
</div>
{{ content_html|raw }}
</body>
</html>