Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New features #515

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 20 additions & 1 deletion DokuPDF.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ class DokuPDF extends Mpdf
* @throws MpdfException
* @throws Exception
*/
public function __construct($pagesize = 'A4', $orientation = 'portrait', $fontsize = 11, $docLang = 'en')
public function __construct($pagesize = 'A4', $orientation = 'portrait', $fontsize = 11, $docLang = 'en', $tpl = 'default')
{
global $conf;
global $lang;
Expand All @@ -52,13 +52,32 @@ public function __construct($pagesize = 'A4', $orientation = 'portrait', $fontsi
$mode = 'UTF-8-s';
}

// Get the default font data
$defaultFontConfig = (new \Mpdf\Config\FontVariables())->getDefaults();
$fontData = $defaultFontConfig['fontdata'];

// Get the default font dirs
$defaultConfig = (new \Mpdf\Config\ConfigVariables())->getDefaults();
$fontDirs = $defaultConfig['fontDir'];

// Append the custom path to it
$tplfonts = DOKU_PLUGIN . 'dw2pdf/tpl/' . $tpl . '/fonts';
if (file_exists($tplfonts . '.php')) {
$fontDirs[] = $tplfonts;

$fontDefs = array($fontData, include($tplfonts . '.php'));
$fontData = array_reduce($fontDefs, 'array_merge', array());
}

parent::__construct([
'mode' => $mode,
'format' => $format,
'default_font_size' => $fontsize,
'ImageProcessorClass' => DokuImageProcessorDecorator::class,
'tempDir' => _MPDF_TEMP_PATH, //$conf['tmpdir'] . '/tmp/dwpdf'
'SHYlang' => $docLang,
'fontDir' => $fontDirs,
'fontdata' => $fontData
]);

$this->autoScriptToLang = true;
Expand Down
211 changes: 201 additions & 10 deletions action.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,25 @@ class action_plugin_dw2pdf extends ActionPlugin
*/
public function __construct()
{
global $JSINFO;

require_once __DIR__ . '/vendor/autoload.php';

$JSINFO['plugins']['dw2pdf']['showexporttemplate'] = $this->getConf('showexporttemplate');

if($this->getConf('showexporttemplate')) {
$templates = [$this->getExportConfig('template')];
$dir = scandir(DOKU_PLUGIN . 'dw2pdf' . DIRECTORY_SEPARATOR . 'tpl');
foreach ($dir as $key => $value)
{
if (is_dir(DOKU_PLUGIN . 'dw2pdf' . DIRECTORY_SEPARATOR . 'tpl' . DIRECTORY_SEPARATOR . $value) && !in_array($value,array(".","..",$this->getExportConfig('template'))))
{
$templates[] = $value;
}
}
$JSINFO['plugins']['dw2pdf']['templates'] = json_encode($templates);
}

$this->tpl = $this->getExportConfig('template');
}

Expand Down Expand Up @@ -435,7 +452,8 @@ protected function generatePDF($cachefile, $event)
$this->getExportConfig('pagesize'),
$this->getExportConfig('orientation'),
$this->getExportConfig('font-size'),
$this->getDocumentLanguage($this->list[0]) //use language of first page
$this->getDocumentLanguage($this->list[0]),
$this->getExportConfig('template') //use language of first page
);

// let mpdf fix local links
Expand Down Expand Up @@ -479,6 +497,7 @@ protected function generatePDF($cachefile, $event)

$styles = '@page { size:auto; ' . $template['page'] . '}';
$styles .= '@page :first {' . $template['first'] . '}';
$styles .= '@page last-page :first {' . $template['last'] . '}';

$styles .= '@page landscape-page { size:landscape }';
$styles .= 'div.dw2pdf-landscape { page:landscape-page }';
Expand Down Expand Up @@ -621,13 +640,14 @@ protected function loadTemplate()
'html' => '',
'page' => '',
'first' => '',
'last' => '',
'cite' => '',
];

// prepare header/footer elements
$html = '';
foreach (['header', 'footer'] as $section) {
foreach (['', '_odd', '_even', '_first'] as $order) {
foreach (['', '_odd', '_even', '_first', '_last'] as $order) {
$file = DOKU_PLUGIN . 'dw2pdf/tpl/' . $this->tpl . '/' . $section . $order . '.html';
if (file_exists($file)) {
$html .= '<htmlpage' . $section . ' name="' . $section . $order . '">' . DOKU_LF;
Expand All @@ -637,6 +657,8 @@ protected function loadTemplate()
// register the needed pseudo CSS
if ($order == '_first') {
$output['first'] .= $section . ': html_' . $section . $order . ';' . DOKU_LF;
} elseif ($order == '_last') {
$output['last'] .= $section . ': html_' . $section . $order . ';' . DOKU_LF;
} elseif ($order == '_even') {
$output['page'] .= 'even-' . $section . '-name: html_' . $section . $order . ';' . DOKU_LF;
} elseif ($order == '_odd') {
Expand All @@ -655,7 +677,6 @@ protected function loadTemplate()
'@TITLE@' => hsc($this->title),
'@WIKI@' => $conf['title'],
'@WIKIURL@' => DOKU_URL,
'@DATE@' => dformat(time()),
'@USERNAME@' => $INFO['userinfo']['name'] ?? '',
'@BASE@' => DOKU_BASE,
'@INC@' => DOKU_INC,
Expand All @@ -677,10 +698,10 @@ protected function loadTemplate()
$output['cover'] .= '<pagebreak />';
}

// cover page
// back page
$backfile = DOKU_PLUGIN . 'dw2pdf/tpl/' . $this->tpl . '/back.html';
if (file_exists($backfile)) {
$output['back'] = '<pagebreak />';
$output['back'] = '<pagebreak page-selector="last-page" />';
$output['back'] .= file_get_contents($backfile);
$output['back'] = str_replace(array_keys($replace), array_values($replace), $output['back']);
$output['back'] = $this->pageDependReplacements($output['back'], $ID);
Expand Down Expand Up @@ -728,6 +749,15 @@ protected function pageDependReplacements($raw, $id)
}
$replace['@PAGEURL@'] = wl($id, $params, true, "&");
$replace['@QRCODE@'] = $qr_code;
$replace['@OLDREVISIONS@'] = $this->changesToHTML($id);
$replace['@DATE@'] = dformat(time());

// @DATE(<date>[, <format>])@
$raw = preg_replace_callback(
'/@DATE\((.*?)(?:,\s*(.*?))?\)@/',
[$this, 'replaceDate'],
$raw
);

$content = $raw;

Expand All @@ -741,10 +771,11 @@ protected function pageDependReplacements($raw, $id)
// plugins may post-process HTML, e.g to clean up unused replacements
$event->advise_after();

// @DATE(<date>[, <format>])@
// @OLDREVISIONS(<html>[, <first>])@
// /@OLDREVISIONS\\(([\\"\'])(.*?[^\\\\])\\1(?:,\\s*(.*?))?\\)@/
$content = preg_replace_callback(
'/@DATE\((.*?)(?:,\s*(.*?))?\)@/',
[$this, 'replaceDate'],
'/@OLDREVISIONS\\(([\\"\'])(.*?[^\\\\])\\1(?:,\\s*(.*?))?\\)@/',
fn($matches) => $this->changesToHTML($id, $matches),
$content
);

Expand All @@ -762,11 +793,171 @@ protected function pageDependReplacements($raw, $id)
public function replaceDate($match)
{
global $conf;
if ($match[1] == '@DATE@') {
$match[1] = time();
}
//no 2nd argument for default date format
if ($match[2] == null) {
if (!isset($match[2])) {
$match[2] = $conf['dformat'];
}
return strftime($match[2], strtotime($match[1]));
return dformat($match[1], $match[2]);
}

/**
* Load page changelog to Array
*
* @param string page changelog file location
* @return array
*/
public function changesToArray($f_changes) {
GLOBAL $auth;

$a_changes = [];
if (file_exists($f_changes)) {
$lines = explode(PHP_EOL, io_readFile($f_changes, false));
for($l = 0; $l < count($lines)-1; $l++) { // Remove last empty line from file
$a_changes[$l] = explode("\t", $lines[$l]);
$a_keys = ['date', 'ip', 'type', 'id', 'user', 'sum', 'extra', 'sizechange'];
if(count($a_changes[$l]) < 8) {
array_splice($a_keys, 7, 1); // Remove missing 'extra' key on revisions created on older DokuWiki releases
}
$a_changes[$l] = array_combine(
$a_keys,
$a_changes[$l]
);

// Username
if (!empty($a_changes[$l]['user'])) {
$userinfo = $auth->getUserData($a_changes[$l]['user'], true);
if (!empty($userinfo)) {
$a_changes[$l]['user'] = $userinfo['name']; // Real Name
}
} else {
// Set "ip" as "user" for Anonymous edits
$a_changes[$l]['user'] = $a_changes[$l]['ip'];
}
}
}
return array_reverse($a_changes); // Latest revision history first
}

/**
* Convert page changelog from Array to HTML
*
* @param int page id
* @param array @OLDREVISIONS@ preg_match array (html, <first>)
* @return string
*/
public function changesToHTML($id, $matches = [null, null]) {
global $lang;

$changes[] = metaFN($id, '.changes');
$f_changes = $changes[0];
$a_changes = $this->changesToArray($f_changes);


$html = $matches[2] ?? null;
$first = $matches[3] ?? null;

// Return last X revisions
if ($first == null) {
$first = count($a_changes);
}

$changes_html = '';
// Render as Table by default
if($html == null) {
$changes_html .= '<table class="dw2pdf-oldrevisions inline" width="100%">';
$changes_html .= '<thead>';
$changes_html .= '<tr>';
$changes_html .= '<th>' . $lang['media_sort_date'] . '</th>';
$changes_html .= '<th>' . $lang['user'] . '</th>';
$changes_html .= '<th>' . $lang['summary'] . '</th>';
$changes_html .= '</tr>';
$changes_html .= '</thead>';
$changes_html .= '<tbody>';
$last_date = '';
$last_author = '';
for($l = 0; $l < $first; ++$l) {
// Summary contains text
if (!empty($a_changes[$l]['sum'])) {
// Wrap Date between <span>
$a_date = explode(" ", dformat($a_changes[$l]['date']));
$a_date_span = [];
for ($i = 0; $i < count($a_date); $i++) {
$a_date_span[] = '<span class="dates date-' . $i . '">' . $a_date[$i] . '</span>';
}

// Wrap User between <span>
$a_user = explode(" ", $a_changes[$l]['user']);
$a_user_span = [];
for ($i = 0; $i < count($a_user); $i++) {
$a_user_span[] = '<span class="names name-' . $i . ($i == count($a_user) ? ' last-name' : '') . '">' . $a_user[$i] . '</span>';
}

$changes_html .= '<span class="lines line-' . $l . ($l == 0 ? ' latest-revision' : '') . '">';
$changes_html .= '<tr>';
$changes_html .= '<td><span class="date' . ($last_date == dformat($a_changes[$l]['date'], '%Y/%m/%d') ? ' same-day' : '') . '">' . implode(" ", $a_date_span) . '</span></td>'; // Date
/* $changes_html .= '<td>' . $a_change['ip'] . '</td>'; // Source IP
$changes_html .= '<td>' . $a_change['type'] . '</td>'; // Operation Type (C - Create, E - Edit)
$changes_html .= '<td>' . $a_change['id'] . '</td>'; // Namespace */
$changes_html .= '<td><span class="author' . ($last_author == $a_changes[$l]['user'] ? ' same-author' : '') . '">' . implode(" ", $a_user_span) . '</span></td>'; // Author
$changes_html .= '<td><span class="sum">' . trim($a_changes[$l]['sum']) . '</span></td>'; // Summary
/* $changes_html .= '<td>' . $a_change['extra'] . '</td>'; // Extra (Flags)
$changes_html .= '<td>' . $a_change['sizechange'] . '</td>'; // Bytes changed */
$changes_html . '</tr>';
$changes_html .= ($l == 0 ? '</span>' : '');

$last_author = $a_changes[$l]['user'];
$last_date = dformat($a_changes[$l]['date'], '%Y/%m/%d');
}
$l++;
}
$changes_html .= '</tbody>';
$changes_html .= '</table>';
} else {
// Reverse array for negative first numbers.
// e.g. -1 returns the revision when the page was first created
if($first < 0) {
$a_changes = array_reverse($a_changes);
$first = abs($first); // Convert number to positive
}

for($l = 0; $l < $first; ++$l) {
$variables = array(
"REVDATE" => $a_changes[$l]['date'],
"REVIP" => $a_changes[$l]['ip'],
"REVTYPE" => $a_changes[$l]['type'],
"REVID" => $a_changes[$l]['id'],
"REVUSER" => $a_changes[$l]['user'],
"REVSUM" => $a_changes[$l]['sum'],
"REVEXTRA" => $a_changes[$l]['extra'],
"REVSIZECHANGE" => $a_changes[$l]['sizechange']
);

$changes_string = $html;
foreach($variables as $key => $value){
$changes_string = str_replace('@'.strtoupper($key).'@', $value, $changes_string);
}

// @REVDATE(<format>)@
$changes_string = preg_replace_callback(
'/@REVDATE\((.*?)\)@/',
fn($datematches) => dformat($a_changes[$l]['date'], $datematches[1]),
$changes_string
);

// @REVNAME(<first>)@
$changes_string = preg_replace_callback(
'/@REVUSER\((.*?)\)@/',
fn($namematches) => ($namematches[1] >= 0 ? explode(" ", $a_changes[$l]['user'])[$namematches[1]] ?? '' : array_reverse(explode(" ", $a_changes[$l]['user']))[abs($namematches[1]+1)] ?? ''),
$changes_string
);

$changes_html .= $changes_string;
}
}
return $changes_html;
}

/**
Expand Down
1 change: 1 addition & 0 deletions conf/default.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,4 @@
$conf['usestyles'] = 'wrap,';
$conf['qrcodescale'] = '1';
$conf['showexportbutton'] = 1;
$conf['showexporttemplate'] = 0;
1 change: 1 addition & 0 deletions conf/metadata.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,4 @@
$meta['usestyles'] = array('string');
$meta['qrcodescale'] = array('string', '_pattern' => '/^(|\d+(\.\d+)?)$/');
$meta['showexportbutton'] = array('onoff');
$meta['showexporttemplate'] = array('onoff');
4 changes: 4 additions & 0 deletions lang/en/lang.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,7 @@
$lang['export_ns'] = 'Export namespace "%s:" to file %s.pdf';
$lang['forbidden'] = "You have no access to these pages: %s.<br/><br/>Use option 'Skip Forbidden Pages' to create your book with the available pages.";
$lang['missingbookcreator'] = 'The Bookcreator Plugin is not installed or is disabled';
$lang['js']['export_pdf_modal'] = "Export to PDF";
$lang['js']['template'] = 'Which template should be used for formatting the PDFs?';
$lang['js']['cancel'] = 'Cancel';
$lang['js']['export'] = 'Export';
1 change: 1 addition & 0 deletions lang/en/settings.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,4 @@
$lang['usestyles'] = 'You can give a comma separated list of plugins of which the <code>style.css</code> or <code>screen.css</code> should be used for PDF generation. By default only <code>print.css</code> and <code>pdf.css</code> are used.';
$lang['qrcodescale'] = 'Size scaling of the embedded QR code. Empty or <code>0</code> to disable.';
$lang['showexportbutton'] = 'Show PDF export button (only when supported by your template)';
$lang['showexporttemplate'] = 'Show PDF export template selection';
5 changes: 5 additions & 0 deletions lang/pt-br/lang.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
*
* @author Daniel Dias Rodrigues <[email protected]>
* @author Schopf <[email protected]>
* @author Eduardo Mozart de Oliveira <[email protected]>
*/
$lang['export_pdf_button'] = 'Exportar para PDF';
$lang['needtitle'] = 'Digite um título.';
Expand All @@ -15,3 +16,7 @@
$lang['export_ns'] = 'Exportar domínio "%s:" para o arquivo %s.pdf';
$lang['forbidden'] = 'Você não tem acesso a essas páginas: %s.<br/><br/>Use a opção \'Ignorar Páginas Proibidas\' para criar seu livro com as páginas disponíveis.';
$lang['missingbookcreator'] = 'O plugin Bookcreator não está instalado ou está desativado';
$lang['js']['export_pdf_modal'] = 'Exportar para PDF';
$lang['js']['template'] = 'Qual modelo deve ser usado para formatar os PDFs?';
$lang['js']['cancel'] = 'Cancelar';
$lang['js']['export'] = 'Exportar';
3 changes: 2 additions & 1 deletion lang/pt-br/settings.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
* @author Schopf <[email protected]>
* @author Juliano Marconi Lanigra <[email protected]>
*/
$lang['pagesize'] = 'O formato de página como suportado pelo mPDF. Normalmente <code>A4</code> ou <code>carta</code>.';
$lang['pagesize'] = 'O formato de página como suportado pelo mPDF. Normalmente <code>A4</code> ou <code>letter</code>.';
$lang['orientation'] = 'A orientação da página.';
$lang['orientation_o_portrait'] = 'Retrato';
$lang['orientation_o_landscape'] = 'Paisagem';
Expand All @@ -25,3 +25,4 @@
$lang['usestyles'] = 'Você pode gerar uma lista de plugins separadas por vírgula nos quais <code>style.css</code> ou <code>screen.css</code> devem ser usadas para a gerar um PDF.';
$lang['qrcodescale'] = 'Escala de tamanho do código QR incorporado. Vazio ou <code>0</code> para desativar.';
$lang['showexportbutton'] = 'Mostrar botão de exportação de PDF (se suportado pelo modelo)';
$lang['showexporttemplate'] = 'Mostrar seleção de template de exportação de PDF';
Loading