diff --git a/assets/ckeditor/plugins/PartDBLabel/PartDBLabelUI.js b/assets/ckeditor/plugins/PartDBLabel/PartDBLabelUI.js index b33f7f39..321aa54b 100644 --- a/assets/ckeditor/plugins/PartDBLabel/PartDBLabelUI.js +++ b/assets/ckeditor/plugins/PartDBLabel/PartDBLabelUI.js @@ -93,6 +93,16 @@ const PLACEHOLDERS = [ ['[[CREATION_DATE]]', 'Creation datetime'], ] }, + { + label: 'Barcodes', + entries: [ + ['[[1D_CONTENT]]', 'Content of the 1D barcodes (like Code 39)'], + ['[[2D_CONTENT]]', 'Content of the 2D barcodes (QR codes)'], + ['[[BARCODE_QR]]', 'QR code linking to this element'], + ['[[BARCODE_C128]]', 'Code 128 barcode linking to this element'], + ['[[BARCODE_C39]]', 'Code 39 barcode linking to this element'], + ] + }, { label: 'Globals', entries: [ @@ -102,7 +112,8 @@ const PLACEHOLDERS = [ ['[[DATE]]', 'Current date'], ['[[TIME]]', 'Current time'], ['[[INSTALL_NAME]]', 'Instance name'], - ['[[TYPE]]', 'Target type'] + ['[[TYPE]]', 'Target type'], + ['[[INSTANCE_URL]]', 'URL of this Part-DB instance'] ], }, ]; diff --git a/assets/ckeditor/plugins/PartDBLabel/lang/de.js b/assets/ckeditor/plugins/PartDBLabel/lang/de.js index e96df8c5..663058f4 100644 --- a/assets/ckeditor/plugins/PartDBLabel/lang/de.js +++ b/assets/ckeditor/plugins/PartDBLabel/lang/de.js @@ -37,6 +37,14 @@ Object.assign( window.CKEDITOR_TRANSLATIONS[ 'de' ].dictionary, { 'Storage location': 'Lagerort', 'Storage location (Full path)': 'Lagerort (Vollständiger Pfad)', + + 'Barcodes': 'Barcodes', + 'Content of the 1D barcodes (like Code 39)': 'Inhalt der 1D Barcodes (z.B. Code 39)', + 'Content of the 2D barcodes (QR codes)': 'Inhalt der 2D Barcodes (QR Codes)', + 'QR code linking to this element': 'QR Code verknüpft mit diesem Element', + 'Code 128 barcode linking to this element': 'Code 128 Barcode verknüpft mit diesem Element', + 'Code 39 barcode linking to this element': 'Code 39 Barcode verknüpft mit diesem Element', + 'Location ID': 'Lagerort ID', 'Name': 'Name', 'Full path': 'Vollständiger Pfad', @@ -50,5 +58,6 @@ Object.assign( window.CKEDITOR_TRANSLATIONS[ 'de' ].dictionary, { 'Current time': 'Aktuelle Zeit', 'Instance name': 'Instanzname', 'Target type': 'Zieltyp', + 'URL of this Part-DB instance': 'URL dieser Part-DB Instanz', } ); \ No newline at end of file diff --git a/src/Services/LabelSystem/BarcodeGenerator.php b/src/Services/LabelSystem/BarcodeGenerator.php index 7e8a4f7f..50b7830c 100644 --- a/src/Services/LabelSystem/BarcodeGenerator.php +++ b/src/Services/LabelSystem/BarcodeGenerator.php @@ -27,16 +27,50 @@ use App\Entity\LabelSystem\LabelOptions; use App\Services\LabelSystem\Barcodes\BarcodeContentGenerator; use Com\Tecnick\Barcode\Barcode; use InvalidArgumentException; +use PhpParser\Node\Stmt\Label; +use Symfony\Component\Mime\MimeTypes; +use Twig\Extra\Html\HtmlExtension; final class BarcodeGenerator { private BarcodeContentGenerator $barcodeContentGenerator; + public function __construct(BarcodeContentGenerator $barcodeContentGenerator) { $this->barcodeContentGenerator = $barcodeContentGenerator; } + public function generateHTMLBarcode(LabelOptions $options, object $target): ?string + { + $svg = $this->generateSVG($options, $target); + $base64 = $this->dataUri($svg, 'image/svg+xml'); + return ''. $this->getContent($options, $target) . ''; + } + + /** + * Creates a data URI (RFC 2397). + * Based on the Twig implementaion from HTMLExtension + * + * Length validation is not performed on purpose, validation should + * be done before calling this filter. + * + * @return string The generated data URI + */ + private function dataUri(string $data, string $mime): string + { + $repr = 'data:'; + + $repr .= $mime; + if (0 === strpos($mime, 'text/')) { + $repr .= ','.rawurlencode($data); + } else { + $repr .= ';base64,'.base64_encode($data); + } + + return $repr; + } + public function generateSVG(LabelOptions $options, object $target): ?string { $barcode = new Barcode(); diff --git a/src/Services/LabelSystem/LabelTextReplacer.php b/src/Services/LabelSystem/LabelTextReplacer.php index be09e8bd..b0b69aa0 100644 --- a/src/Services/LabelSystem/LabelTextReplacer.php +++ b/src/Services/LabelSystem/LabelTextReplacer.php @@ -71,7 +71,7 @@ final class LabelTextReplacer public function replace(string $lines, object $target): string { $patterns = [ - '/(\[\[[A-Z_]+\]\])/' => function ($match) use ($target) { + '/(\[\[[A-Z_0-9]+\]\])/' => function ($match) use ($target) { return $this->handlePlaceholder($match[0], $target); }, ]; diff --git a/src/Services/LabelSystem/PlaceholderProviders/BarcodeProvider.php b/src/Services/LabelSystem/PlaceholderProviders/BarcodeProvider.php new file mode 100644 index 00000000..573d578b --- /dev/null +++ b/src/Services/LabelSystem/PlaceholderProviders/BarcodeProvider.php @@ -0,0 +1,59 @@ +barcodeGenerator = $barcodeGenerator; + $this->barcodeContentGenerator = $barcodeContentGenerator; + } + + public function replace(string $placeholder, object $label_target, array $options = []): ?string + { + if ('[[1D_CONTENT]]' === $placeholder) { + try { + return $this->barcodeContentGenerator->get1DBarcodeContent($label_target); + } catch (\InvalidArgumentException $e) { + return 'ERROR!'; + } + } + + if ('[[2D_CONTENT]]' === $placeholder) { + try { + return $this->barcodeContentGenerator->getURLContent($label_target); + } catch (\InvalidArgumentException $e) { + return 'ERROR!'; + } + } + + if ('[[BARCODE_QR]]' === $placeholder) { + $label_options = new LabelOptions(); + $label_options->setBarcodeType('qr'); + return $this->barcodeGenerator->generateHTMLBarcode($label_options, $label_target); + } + + if ('[[BARCODE_C39]]' === $placeholder) { + $label_options = new LabelOptions(); + $label_options->setBarcodeType('code39'); + return $this->barcodeGenerator->generateHTMLBarcode($label_options, $label_target); + } + + if ('[[BARCODE_C128]]' === $placeholder) { + $label_options = new LabelOptions(); + $label_options->setBarcodeType('code128'); + return $this->barcodeGenerator->generateHTMLBarcode($label_options, $label_target); + } + + return null; + } +} \ No newline at end of file diff --git a/src/Services/LabelSystem/PlaceholderProviders/GlobalProviders.php b/src/Services/LabelSystem/PlaceholderProviders/GlobalProviders.php index 813595aa..65db3788 100644 --- a/src/Services/LabelSystem/PlaceholderProviders/GlobalProviders.php +++ b/src/Services/LabelSystem/PlaceholderProviders/GlobalProviders.php @@ -27,6 +27,8 @@ use App\Entity\UserSystem\User; use DateTime; use IntlDateFormatter; use Locale; +use Symfony\Component\Routing\Generator\UrlGenerator; +use Symfony\Component\Routing\Generator\UrlGeneratorInterface; use Symfony\Component\Security\Core\Security; /** @@ -36,11 +38,13 @@ final class GlobalProviders implements PlaceholderProviderInterface { private string $partdb_title; private Security $security; + private UrlGeneratorInterface $url_generator; - public function __construct(string $partdb_title, Security $security) + public function __construct(string $partdb_title, Security $security, UrlGeneratorInterface $url_generator) { $this->partdb_title = $partdb_title; $this->security = $security; + $this->url_generator = $url_generator; } public function replace(string $placeholder, object $label_target, array $options = []): ?string @@ -101,6 +105,10 @@ final class GlobalProviders implements PlaceholderProviderInterface return $formatter->format($now); } + if ('[[INSTANCE_URL]]' === $placeholder) { + return $this->url_generator->generate('homepage', [], UrlGenerator::ABSOLUTE_URL); + } + return null; } }