Adjustments for design and dom elements / attributes

This commit is contained in:
David Bomba 2025-01-13 14:16:55 +11:00
parent 8ce6e6a44e
commit 406cc52279
21 changed files with 193 additions and 117 deletions

View File

@ -55,8 +55,8 @@ class EpcQrGenerator
$qr = $writer->writeString($this->encodeMessage(), 'utf-8'); $qr = $writer->writeString($this->encodeMessage(), 'utf-8');
return "<svg viewBox='0 0 200 200' width='200' height='200' x='0' y='0' xmlns='http://www.w3.org/2000/svg'> return htmlspecialchars("<svg viewBox='0 0 200 200' width='200' height='200' x='0' y='0' xmlns='http://www.w3.org/2000/svg'>
<rect x='0' y='0' width='100%'' height='100%' />{$qr}</svg>"; <rect x='0' y='0' width='100%'' height='100%' />{$qr}</svg>");
} catch (\Throwable $e) { } catch (\Throwable $e) {
nlog("EPC QR failure => ".$e->getMessage()); nlog("EPC QR failure => ".$e->getMessage());

View File

@ -172,7 +172,7 @@ class SwissQrGenerator
->setPrintable(false) ->setPrintable(false)
->getPaymentPart(); ->getPaymentPart();
return $html; return htmlspecialchars($html);
} catch (\Exception $e) { } catch (\Exception $e) {
// if (is_iterable($qrBill->getViolations())) { // if (is_iterable($qrBill->getViolations())) {

View File

@ -212,6 +212,7 @@ class PreviewController extends BaseController
->build(); ->build();
if (request()->query('html') == 'true') { if (request()->query('html') == 'true') {
return $maker->getCompiledHTML(); return $maker->getCompiledHTML();
} }

View File

@ -83,6 +83,7 @@ class PdfBuilder
private function removeEmptyElements(): self private function removeEmptyElements(): self
{ {
$elements =[ $elements =[
'product-table', 'task-table', 'delivery-note-table', 'product-table', 'task-table', 'delivery-note-table',
'statement-invoice-table', 'statement-payment-table', 'statement-aging-table-totals', 'statement-invoice-table', 'statement-payment-table', 'statement-aging-table-totals',
@ -96,45 +97,59 @@ class PdfBuilder
if ($el && $el->childElementCount === 0) { if ($el && $el->childElementCount === 0) {
$el->parentNode->removeChild($el); // This removes the element completely $el->parentNode->removeChild($el); // This removes the element completely
// $el->setAttribute('style', 'display: none !important;');
} }
} }
// $xpath = new \DOMXPath($this->document);
// $elements = $xpath->query('//*[@data-state="encoded-html"]');
// foreach ($elements as $element) { $xpath = new \DOMXPath($this->document);
$elements = $xpath->query('//*[@data-state="encoded-html"]');
// // Decode the HTML content foreach ($elements as $element) {
// $html = htmlspecialchars_decode($element->textContent, ENT_QUOTES | ENT_HTML5);
// $html = str_ireplace(['<br>'], '<br/>', $html);
// // Create a temporary document to properly parse the HTML // Decode the HTML content
// $temp = new \DOMDocument(); $html = htmlspecialchars_decode($element->textContent, ENT_QUOTES | ENT_HTML5);
$html = str_ireplace(['<br>','<?xml encoding="UTF-8">'], ['<br/>',''], $html);
// // Add UTF-8 wrapper and div container // Create a temporary document to properly parse the HTML
// $wrappedHtml = '<?xml encoding="UTF-8"><div>' . $html . '</div>'; $temp = new \DOMDocument();
// // Load the HTML, suppressing any parsing warnings // Add UTF-8 wrapper and div container
// @$temp->loadHTML($wrappedHtml, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD); $wrappedHtml = '<?xml encoding="UTF-8"><div>' . $html . '</div>';
// // Import the div's contents // Load the HTML, suppressing any parsing warnings
// $imported = $this->document->importNode($temp->getElementsByTagName('div')->item(0), true); @$temp->loadHTML($wrappedHtml, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
// // Clear existing content of the element // Import the div's contents
// while ($element->firstChild) { $imported = $this->document->importNode($temp->getElementsByTagName('div')->item(0), true);
// $element->removeChild($element->firstChild);
// }
// // Append the new content to the element // Clear existing content - more efficient
// $element->appendChild($imported); $element->textContent = '';
// Get the first div's content
$divContent = $temp->getElementsByTagName('div')->item(0);
if ($divContent) {
// Import all nodes from the temporary div
foreach ($divContent->childNodes as $child) {
$imported = $this->document->importNode($child, true);
$element->appendChild($imported);
}
} else {
// Fallback - import the entire content if no div found
$imported = $this->document->importNode($temp->documentElement, true);
$element->appendChild($imported);
}
}
// }
return $this; return $this;
} }
/** /**
* Final method to get compiled HTML. * Final method to get compiled HTML.
* *
@ -1131,7 +1146,7 @@ class PdfBuilder
} }
if(array_key_exists($column, $column_visibility)){ if(array_key_exists($column, $column_visibility)){
return $column_visibility[$column] ? false: true; return !$column_visibility[$column];
} }
return true; return true;
@ -1386,9 +1401,11 @@ class PdfBuilder
$elements = [ $elements = [
['element' => 'div', 'properties' => ['style' => 'display: flex; flex-direction: column;'], 'elements' => [ ['element' => 'div', 'properties' => ['style' => 'display: flex; flex-direction: column;'], 'elements' => [
['element' => 'p', 'content' => strtr(str_replace(["labels", "values"], ["",""], $_variables['values']['$entity.public_notes']), $_variables), 'properties' => ['data-ref' => 'total_table-public_notes', 'style' => 'text-align: left;']], ['element' => 'div', 'properties' => ['data-ref' => 'total_table-public_notes', 'style' => 'text-align: left;'], 'elements' => [
['element' => 'p', 'content' => '', 'properties' => ['style' => 'text-align: left; display: flex; flex-direction: column; page-break-inside: auto;'], 'elements' => [ ['element' => 'span', 'content' => strtr(str_replace(["labels", "values"], ["",""], $_variables['values']['$entity.public_notes']), $_variables)]
['element' => 'span', 'content' => '$entity.terms_label: ', 'properties' => ['data-ref' => 'total_table-terms-label', 'style' => "font-weight: bold; text-align: left; margin-top: 1rem; {$show_terms_label}"]], ]],
['element' => 'div', 'content' => '', 'properties' => ['style' => 'text-align: left; display: flex; flex-direction: column; page-break-inside: auto;'], 'elements' => [
['element' => 'span', 'content' => '$entity.terms_label: ', 'properties' => ['data-ref' => 'total_table-terms-label', 'style' => "text-align: left; margin-top: 1rem; {$show_terms_label}"]],
['element' => 'span', 'content' => strtr(str_replace("labels", "", $_variables['values']['$entity.terms']), $_variables['labels']), 'properties' => ['data-ref' => 'total_table-terms', 'style' => 'text-align: left;']], ['element' => 'span', 'content' => strtr(str_replace("labels", "", $_variables['values']['$entity.terms']), $_variables['labels']), 'properties' => ['data-ref' => 'total_table-terms', 'style' => 'text-align: left;']],
]], ]],
['element' => 'img', 'properties' => ['style' => 'max-width: 50%; height: auto;', 'src' => '$contact.signature', 'id' => 'contact-signature']], ['element' => 'img', 'properties' => ['style' => 'max-width: 50%; height: auto;', 'src' => '$contact.signature', 'id' => 'contact-signature']],
@ -1495,6 +1512,7 @@ class PdfBuilder
['element' => 'span', 'content' => ''], ['element' => 'span', 'content' => ''],
]]; ]];
return $elements; return $elements;
} }
@ -2037,11 +2055,15 @@ class PdfBuilder
$html = strtr($this->getCompiledHTML(), $this->service->html_variables['labels']); $html = strtr($this->getCompiledHTML(), $this->service->html_variables['labels']);
$html = strtr($html, $this->service->html_variables['values']); $html = strtr($html, $this->service->html_variables['values']);
$html = htmlspecialchars_decode($html, ENT_QUOTES | ENT_HTML5); //old block
$html = str_ireplace(['<br>'], '<br/>', $html); @$this->document->loadHTML(mb_convert_encoding($html, 'HTML-ENTITIES', 'UTF-8'));
@$this->document->loadHTML('<?xml encoding="UTF-8">'.$html, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD); //new block
// $html = htmlspecialchars_decode($html, ENT_QUOTES | ENT_HTML5);
// $html = str_ireplace(['<br>','<?xml encoding="UTF-8">'], ['<br/>',''], $html);
// @$this->document->loadHTML('<?xml encoding="UTF-8">'.$html, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
//continues
$this->document->saveHTML(); $this->document->saveHTML();
return $this; return $this;

View File

@ -90,7 +90,10 @@ class PdfService
public function getPdf() public function getPdf()
{ {
try { try {
$pdf = $this->resolvePdfEngine($this->getHtml());
$html = $this->getHtml();
// nlog($html);
$pdf = $this->resolvePdfEngine($html);
$numbered_pdf = $this->pageNumbering($pdf, $this->company); $numbered_pdf = $this->pageNumbering($pdf, $this->company);

View File

@ -40,6 +40,7 @@ class Purify
'polygon', 'g', 'text', 'tspan', 'defs', 'use', 'title', 'polygon', 'g', 'text', 'tspan', 'defs', 'use', 'title',
]; ];
private static array $allowed_attributes = [ private static array $allowed_attributes = [
// Global Attributes // Global Attributes
'class' => ['*'], 'class' => ['*'],
@ -55,7 +56,7 @@ class Purify
'data-state' => ['*'], 'data-state' => ['*'],
//SVG //SVG
'd' => ['*'], 'd' => ['*'],
'viewBox' => ['*'], 'viewBox' => ['*'],
'xmlns' => ['http://www.w3.org/2000/svg'], 'xmlns' => ['http://www.w3.org/2000/svg'],
'fill' => ['*'], 'fill' => ['*'],
@ -71,7 +72,7 @@ class Purify
'preserveAspectRatio' => ['*'], 'preserveAspectRatio' => ['*'],
'version' => ['*'], 'version' => ['*'],
'xlink:href' => ['#*'], // Only allow internal references 'xlink:href' => ['#*'], // Only allow internal references
'fill-rule' => ['nonzero', 'evenodd'],
// Layout & Presentation // Layout & Presentation
'align' => ['left', 'center', 'right', 'justify'], 'align' => ['left', 'center', 'right', 'justify'],
'valign' => ['top', 'middle', 'bottom', 'baseline'], 'valign' => ['top', 'middle', 'bottom', 'baseline'],
@ -115,6 +116,8 @@ class Purify
'content' => ['*'], 'content' => ['*'],
'http-equiv' => ['*'], 'http-equiv' => ['*'],
'viewport' => ['*'], 'viewport' => ['*'],
'xmlns' => ['http://www.w3.org/2000/svg'],
]; ];
private static array $dangerous_css_patterns = [ private static array $dangerous_css_patterns = [
@ -214,6 +217,24 @@ class Purify
return implode('; ', $safe_declarations); return implode('; ', $safe_declarations);
} }
private static array $dangerous_svg_elements = [
'script',
'handler',
'foreignObject',
'annotation-xml',
'color-profile',
'style', // or carefully sanitize if needed
'onload',
'onerror',
'onunload',
'onabort'
];
private static function isDangerousSvgElement(string $tagName): bool
{
return in_array(strtolower($tagName), self::$dangerous_svg_elements);
}
public static function clean(string $html): string public static function clean(string $html): string
{ {
if(config('ninja.disable_purify_html')){ if(config('ninja.disable_purify_html')){
@ -221,9 +242,9 @@ class Purify
} }
$html = str_replace('%24', '$', $html); $html = str_replace('%24', '$', $html);
libxml_use_internal_errors(true); libxml_use_internal_errors(true);
libxml_disable_entity_loader(true); libxml_disable_entity_loader(true);
// nlog("pre purify => {$html}");
$document = new \DOMDocument(); $document = new \DOMDocument();
@$document->loadHTML(htmlspecialchars_decode(htmlspecialchars($html, ENT_QUOTES, 'UTF-8'))); @$document->loadHTML(htmlspecialchars_decode(htmlspecialchars($html, ENT_QUOTES, 'UTF-8')));
@ -267,10 +288,24 @@ class Purify
$current_attributes[$attr->name] = $attr->value; $current_attributes[$attr->name] = $attr->value;
} }
// Handle SVG node separately
if ($node->tagName === 'svg') {
// Keep only allowed SVG attributes
$current_attributes = [];
foreach ($node->attributes as $attr) {
if (in_array($attr->name, self::$dangerous_svg_elements)) {
$node->removeAttribute($attr->name);
}
}
} else {
// First, remove ALL attributes from the node // First, remove ALL attributes from the node
while ($node->attributes->length > 0) { while ($node->attributes->length > 0) {
$attr = $node->attributes->item(0); $attr = $node->attributes->item(0);
$node->removeAttribute($attr->nodeName); $node->removeAttribute($attr->nodeName);
}
} }
// Then add back only the allowed attributes // Then add back only the allowed attributes
@ -361,15 +396,18 @@ class Purify
$html = str_replace('%24', '$', $document->saveHTML()); $html = str_replace('%24', '$', $document->saveHTML());
// nlog("post purify => {$html}");
return $html; return $html;
} catch (\Exception $e) { } catch (\Exception $e) {
nlog('Error cleaning HTML: ' . $e->getMessage()); nlog('Error cleaning HTML: ' . $e->getMessage());
libxml_disable_entity_loader(false);
libxml_clear_errors();
throw new \RuntimeException('HTML sanitization failed'); throw new \RuntimeException('HTML sanitization failed');
}finally { } finally {
// Restore original setting
libxml_disable_entity_loader(false); libxml_disable_entity_loader(false);
libxml_clear_errors(); libxml_clear_errors();
} }

View File

@ -839,7 +839,6 @@ class Design extends BaseDesign
} }
} }
$visible_elements = array_filter($elements, function ($element) { $visible_elements = array_filter($elements, function ($element) {
return $element['properties']['visi'] ?? true; return $element['properties']['visi'] ?? true;
}); });
@ -883,7 +882,7 @@ class Design extends BaseDesign
} }
if(array_key_exists($column, $column_visibility)){ if(array_key_exists($column, $column_visibility)){
return $column_visibility[$column] ? false: true; return !$column_visibility[$column];
} }
return true; return true;
@ -957,20 +956,6 @@ class Design extends BaseDesign
} }
} }
// Then, filter the elements array
$element['elements'] = array_map(function ($el) {
if (isset($el['properties']['visi'])) {
if ($el['properties']['visi'] === false) {
$el['properties']['style'] = 'display: none;';
}
unset($el['properties']['visi']);
}
return $el;
}, $element['elements']);
$elements[] = $element;
} }
return $elements; return $elements;
@ -1030,7 +1015,15 @@ class Design extends BaseDesign
$element['elements'][] = ['element' => 'td', 'content' => $row[$cell], 'properties' => ['data-ref' => 'product_table-product.tax2-td', 'visi' => $this->visibilityCheck($column_visibility, $cell)]]; $element['elements'][] = ['element' => 'td', 'content' => $row[$cell], 'properties' => ['data-ref' => 'product_table-product.tax2-td', 'visi' => $this->visibilityCheck($column_visibility, $cell)]];
} elseif ($cell == '$product.tax_rate3') { } elseif ($cell == '$product.tax_rate3') {
$element['elements'][] = ['element' => 'td', 'content' => $row[$cell], 'properties' => ['data-ref' => 'product_table-product.tax3-td', 'visi' => $this->visibilityCheck($column_visibility, $cell)]]; $element['elements'][] = ['element' => 'td', 'content' => $row[$cell], 'properties' => ['data-ref' => 'product_table-product.tax3-td', 'visi' => $this->visibilityCheck($column_visibility, $cell)]];
} elseif ($cell == '$product.unit_cost' || $cell == '$task.rate') { } elseif ($cell == '$task.discount' && !$this->company->enable_product_discount) {
$element['elements'][] = ['element' => 'td', 'content' => $row['$task.discount'], 'properties' => ['data-ref' => 'task_table-task.discount-td', 'style' => 'display: none;']];
} elseif ($cell == '$task.tax_rate1') {
$element['elements'][] = ['element' => 'td', 'content' => $row[$cell], 'properties' => ['data-ref' => 'task_table-task.tax1-td', 'visi' => $this->visibilityCheck($column_visibility, $cell)]];
} elseif ($cell == '$task.tax_rate2') {
$element['elements'][] = ['element' => 'td', 'content' => $row[$cell], 'properties' => ['data-ref' => 'task_table-task.tax2-td', 'visi' => $this->visibilityCheck($column_visibility, $cell)]];
} elseif ($cell == '$task.tax_rate3') {
$element['elements'][] = ['element' => 'td', 'content' => $row[$cell], 'properties' => ['data-ref' => 'task_table-task.tax3-td', 'visi' => $this->visibilityCheck($column_visibility, $cell)]];
}elseif ($cell == '$product.unit_cost' || $cell == '$task.rate') {
$element['elements'][] = ['element' => 'td', 'content' => $row[$cell], 'properties' => ['style' => 'white-space: nowrap;', 'data-ref' => "{$_type}_table-" . substr($cell, 1) . '-td', 'visi' => $this->visibilityCheck($column_visibility, $cell)]]; $element['elements'][] = ['element' => 'td', 'content' => $row[$cell], 'properties' => ['style' => 'white-space: nowrap;', 'data-ref' => "{$_type}_table-" . substr($cell, 1) . '-td', 'visi' => $this->visibilityCheck($column_visibility, $cell)]];
} else { } else {
$element['elements'][] = ['element' => 'td', 'content' => $row[$cell], 'properties' => ['data-ref' => "{$_type}_table-" . substr($cell, 1) . '-td', 'visi' => $this->visibilityCheck($column_visibility, $cell)]]; $element['elements'][] = ['element' => 'td', 'content' => $row[$cell], 'properties' => ['data-ref' => "{$_type}_table-" . substr($cell, 1) . '-td', 'visi' => $this->visibilityCheck($column_visibility, $cell)]];
@ -1038,7 +1031,19 @@ class Design extends BaseDesign
} }
} }
// Then, filter the elements array
$element['elements'] = array_map(function ($el) {
if (isset($el['properties']['visi'])) {
if ($el['properties']['visi'] === false) {
$el['properties']['style'] = 'display: none;';
}
unset($el['properties']['visi']);
}
return $el;
}, $element['elements']);
$elements[] = $element; $elements[] = $element;
} }
$document = null; $document = null;
@ -1058,10 +1063,11 @@ class Design extends BaseDesign
}); });
// Transform the items first // Transform the items first
$transformed_items = $this->transformLineItems($filtered_items, $transformed_items = $this->transformLineItems(
$filtered_items->toArray(),
$type_id === '1' ? '$product' : '$task' $type_id === '1' ? '$product' : '$task'
); );
nlog($transformed_items);
$columns = []; $columns = [];
// Initialize all columns as empty // Initialize all columns as empty
@ -1105,9 +1111,12 @@ class Design extends BaseDesign
$variables = $this->context['pdf_variables']['total_columns']; $variables = $this->context['pdf_variables']['total_columns'];
$show_terms_label = $this->entityVariableCheck('$entity.terms') ? 'display: none;' : ''; $show_terms_label = $this->entityVariableCheck('$entity.terms') ? 'display: none;' : '';
$elements = [ $elements = [
['element' => 'div', 'properties' => ['style' => 'display: flex; flex-direction: column;'], 'elements' => [ ['element' => 'div', 'properties' => ['style' => 'display: flex; flex-direction: column;'], 'elements' => [
['element' => 'p', 'content' => strtr(str_replace(["labels","values"], ["",""], $_variables['values']['$entity.public_notes']), $_variables), 'properties' => ['data-ref' => 'total_table-public_notes', 'style' => 'text-align: left;']], ['element' => 'p', 'properties' => ['data-ref' => 'total_table-public_notes', 'style' => 'text-align: left;'], 'elements' => [
['element' => 'span', 'content' => strtr(str_replace(["labels", "values"], ["",""], $_variables['values']['$entity.public_notes']), $_variables)]
]],
['element' => 'p', 'content' => '', 'properties' => ['style' => 'text-align: left; display: flex; flex-direction: column; page-break-inside: auto;'], 'elements' => [ ['element' => 'p', 'content' => '', 'properties' => ['style' => 'text-align: left; display: flex; flex-direction: column; page-break-inside: auto;'], 'elements' => [
['element' => 'span', 'content' => '$entity.terms_label: ', 'properties' => ['data-ref' => 'total_table-terms-label', 'style' => "font-weight: bold; text-align: left; margin-top: 1rem; {$show_terms_label}"]], ['element' => 'span', 'content' => '$entity.terms_label: ', 'properties' => ['data-ref' => 'total_table-terms-label', 'style' => "font-weight: bold; text-align: left; margin-top: 1rem; {$show_terms_label}"]],
['element' => 'span', 'content' => strtr(str_replace("labels", "", $_variables['values']['$entity.terms']), $_variables['labels']), 'properties' => ['data-ref' => 'total_table-terms', 'style' => 'text-align: left;']], ['element' => 'span', 'content' => strtr(str_replace("labels", "", $_variables['values']['$entity.terms']), $_variables['labels']), 'properties' => ['data-ref' => 'total_table-terms', 'style' => 'text-align: left;']],
@ -1192,9 +1201,6 @@ class Design extends BaseDesign
} }
} elseif (Str::startsWith($variable, '$custom_surcharge')) { } elseif (Str::startsWith($variable, '$custom_surcharge')) {
$_variable = ltrim($variable, '$'); // $custom_surcharge1 -> custom_surcharge1 $_variable = ltrim($variable, '$'); // $custom_surcharge1 -> custom_surcharge1
//07/09/2023 don't show custom values if they are empty
// $visible = intval($this->entity->{$_variable}) != 0;
$visible = intval(str_replace(['0','.'], '', $this->entity->{$_variable})) != 0; $visible = intval(str_replace(['0','.'], '', $this->entity->{$_variable})) != 0;
$elements[1]['elements'][] = ['element' => 'div', 'elements' => [ $elements[1]['elements'][] = ['element' => 'div', 'elements' => [

View File

@ -75,7 +75,7 @@ class PdfMaker
$ts = new TemplateService(); $ts = new TemplateService();
if (isset($this->options['client'])) { if (isset($this->options['client']) && !empty($this->options['client'])) {
$client = $this->options['client']; $client = $this->options['client'];
try { try {
$ts->setCompany($client->company); $ts->setCompany($client->company);
@ -85,7 +85,7 @@ class PdfMaker
} }
} }
if (isset($this->options['vendor'])) { if (isset($this->options['vendor']) && !empty($this->options['vendor'])) {
$vendor = $this->options['vendor']; $vendor = $this->options['vendor'];
try { try {
$ts->setCompany($vendor->company); $ts->setCompany($vendor->company);
@ -139,40 +139,48 @@ class PdfMaker
} }
// $xpath = new \DOMXPath($this->document); $xpath = new \DOMXPath($this->document);
// $elements = $xpath->query('//*[@data-state="encoded-html"]'); $elements = $xpath->query('//*[@data-state="encoded-html"]');
// foreach ($elements as $element) { foreach ($elements as $element) {
// // Decode the HTML content // Decode the HTML content
// $html = htmlspecialchars_decode($element->textContent, ENT_QUOTES | ENT_HTML5); $html = htmlspecialchars_decode($element->textContent, ENT_QUOTES | ENT_HTML5);
// $html = str_ireplace(['<br>'], '<br/>', $html); $html = str_ireplace(['<br>','<?xml encoding="UTF-8">'], ['<br/>',''], $html);
// // Create a temporary document to properly parse the HTML // Create a temporary document to properly parse the HTML
// $temp = new \DOMDocument(); $temp = new \DOMDocument();
// // Add UTF-8 wrapper and div container // Add UTF-8 wrapper and div container
// $wrappedHtml = '<?xml encoding="UTF-8"><div>' . $html . '</div>'; $wrappedHtml = '<?xml encoding="UTF-8"><div>' . $html . '</div>';
// // Load the HTML, suppressing any parsing warnings // Load the HTML, suppressing any parsing warnings
// @$temp->loadHTML($wrappedHtml, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD); @$temp->loadHTML($wrappedHtml, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
// // Import the div's contents // Import the div's contents
// $imported = $this->document->importNode($temp->getElementsByTagName('div')->item(0), true); $imported = $this->document->importNode($temp->getElementsByTagName('div')->item(0), true);
// // Clear existing content of the element // Clear existing content - more efficient
// while ($element->firstChild) { $element->textContent = '';
// $element->removeChild($element->firstChild); // Get the first div's content
// } $divContent = $temp->getElementsByTagName('div')->item(0);
// // Append the new content to the element if ($divContent) {
// $element->appendChild($imported); // Import all nodes from the temporary div
foreach ($divContent->childNodes as $child) {
// } $imported = $this->document->importNode($child, true);
$element->appendChild($imported);
}
} else {
// Fallback - import the entire content if no div found
$imported = $this->document->importNode($temp->documentElement, true);
$element->appendChild($imported);
}
}
return $this; return $this;
} }

View File

@ -143,13 +143,15 @@ trait PdfMakerUtilities
$html = strtr($html, $variables['values']); $html = strtr($html, $variables['values']);
// @$this->document->loadHTML(mb_convert_encoding($html, 'HTML-ENTITIES', 'UTF-8')); //old block
@$this->document->loadHTML(mb_convert_encoding($html, 'HTML-ENTITIES', 'UTF-8'));
$html = htmlspecialchars_decode($html, ENT_QUOTES | ENT_HTML5); //new block
$html = str_ireplace(['<br>'], '<br/>', $html); // $html = htmlspecialchars_decode($html, ENT_QUOTES | ENT_HTML5);
// $html = str_ireplace(['<br>'], '<br/>', $html);
@$this->document->loadHTML('<?xml encoding="UTF-8">'.$html, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD); // @$this->document->loadHTML('<?xml encoding="UTF-8">'.$html, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
//continues
$this->document->saveHTML(); $this->document->saveHTML();
} }

View File

@ -95,7 +95,6 @@ trait PdfMaker
$html = str_ireplace(['file:/', 'iframe', '<embed', '&lt;embed', '&lt;object', '<object', '127.0.0.1', 'localhost', '<?xml encoding="UTF-8">'], '', $html); $html = str_ireplace(['file:/', 'iframe', '<embed', '&lt;embed', '&lt;object', '<object', '127.0.0.1', 'localhost', '<?xml encoding="UTF-8">'], '', $html);
// nlog($html);
$generated = $pdf $generated = $pdf
->setHtml($html) ->setHtml($html)
->generate(); ->generate();

View File

@ -414,7 +414,7 @@
} }
#qr-bill{ #qr-bill{
width:100%; width:100% !important;
} }
/** Useful snippets, uncomment to enable. **/ /** Useful snippets, uncomment to enable. **/

View File

@ -348,7 +348,7 @@
} }
#qr-bill{ #qr-bill{
width:100%; width:100% !important;
} }

View File

@ -348,6 +348,10 @@
.pqrcode {} .pqrcode {}
#qr-bill{
width:100% !important;
}
/** Useful snippets, uncomment to enable. **/ /** Useful snippets, uncomment to enable. **/
/** Hide company logo **/ /** Hide company logo **/

View File

@ -37,17 +37,6 @@
padding: 0; padding: 0;
} }
#qr-bill {
width:100% !important;
box-sizing: border-box;
border-collapse: collapse;
color: #000;
}
#qr-bill td {
max-width: none;
}
.header-container { .header-container {
display: grid; display: grid;
grid-template-columns: repeat(3, 1fr); grid-template-columns: repeat(3, 1fr);
@ -360,7 +349,7 @@
} }
#qr-bill{ #qr-bill{
width:100%; width:100% !important;
} }
/** Useful snippets, uncomment to enable. **/ /** Useful snippets, uncomment to enable. **/

View File

@ -311,7 +311,7 @@
} }
#qr-bill{ #qr-bill{
width:100%; width:100% !important;
} }
/** Useful snippets, uncomment to enable. **/ /** Useful snippets, uncomment to enable. **/

View File

@ -331,7 +331,7 @@
} }
#qr-bill{ #qr-bill{
width:100%; width:100% !important;
} }
/** Useful snippets, uncomment to enable. **/ /** Useful snippets, uncomment to enable. **/

View File

@ -392,7 +392,7 @@
} }
#qr-bill{ #qr-bill{
width:100%; width:100% !important;
} }
/** Useful snippets, uncomment to enable. **/ /** Useful snippets, uncomment to enable. **/

View File

@ -395,7 +395,7 @@
} }
#qr-bill{ #qr-bill{
width:100%; width:100% !important;
} }
/** Useful snippets, uncomment to enable. **/ /** Useful snippets, uncomment to enable. **/

View File

@ -354,7 +354,7 @@
#qr-bill{ #qr-bill{
width:100%; width:100% !important;
} }

View File

@ -383,6 +383,10 @@
} }
#qr-bill{
width:100% !important;
}
/** Useful snippets, uncomment to enable. **/ /** Useful snippets, uncomment to enable. **/
/** Hide company logo **/ /** Hide company logo **/

View File

@ -387,8 +387,8 @@
} }
#qr-bill{ #qr-bill{
width:100%; width:100% !important;
} }
/** Useful snippets, uncomment to enable. **/ /** Useful snippets, uncomment to enable. **/