PluginProbe
WCPOS – Point of Sale (POS) plugin for WooCommerce / 1.10.20
WCPOS – Point of Sale (POS) plugin for WooCommerce v1.10.20
1.10.20 1.10.19 1.10.18 1.10.17 1.10.16 1.10.15 1.10.13 1.10.14 1.10.12 1.10.11 1.10.10 1.10.9 1.10.8 untagged-3d9b7ccddc54df87c672 1.10.7 1.10.6 1.10.5 1.10.3 1.10.4 1.10.2 1.10.1 1.10.0 1.9.17 1.9.15 1.9.16 All 164 releases
woocommerce-pos / includes / Templates / Thermal / Thermal_Emitter_Support.php

Thermal_Emitter_Support.php in WCPOS – Point of Sale (POS) plugin for WooCommerce 1.10.20, at includes/Templates/Thermal/Thermal_Emitter_Support.php

124 lines 3.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Shared AST walking and byte-emitter text support for WCPOS.
4 *
5 * @package WCPOS\WooCommercePOS
6 */
7
8 namespace WCPOS\WooCommercePOS\Templates\Thermal;
9
10 /**
11 * Private emitter helpers; encoding and printer state stay with each emitter.
12 */
13 trait Thermal_Emitter_Support {
14
15 /**
16 * Walk a list of AST nodes.
17 *
18 * @param array $nodes The AST nodes.
19 *
20 * @return void
21 */
22 private function walk_nodes( array $nodes ): void {
23 foreach ( $nodes as $node ) {
24 if ( \is_array( $node ) ) {
25 $this->walk_node( $node );
26 }
27 }
28 }
29
30 /**
31 * Insert an auto drawer node before the first trailing cut when enabled.
32 *
33 * @param array $nodes AST nodes.
34 *
35 * @return array
36 */
37 private function nodes_with_auto_drawer( array $nodes ): array {
38 if ( empty( $this->options['auto_open_drawer'] ) || $this->nodes_contain_drawer( $nodes ) ) {
39 return $nodes;
40 }
41
42 $drawer = array(
43 'type' => 'drawer',
44 'connector' => \WCPOS\WooCommercePOS\Services\Print_Job_Service::normalize_drawer_connector( (string) ( $this->options['drawer_connector'] ?? 'pin2' ) ),
45 );
46
47 for ( $i = count( $nodes ) - 1; $i >= 0; $i-- ) {
48 $type = isset( $nodes[ $i ]['type'] ) ? (string) $nodes[ $i ]['type'] : '';
49 if ( 'cut' === $type ) {
50 array_splice( $nodes, $i, 0, array( $drawer ) );
51 return $nodes;
52 }
53 if ( in_array( $type, array( 'feed' ), true ) ) {
54 continue;
55 }
56 break;
57 }
58
59 $nodes[] = $drawer;
60 return $nodes;
61 }
62
63 /**
64 * Whether a node list contains an explicit drawer node.
65 *
66 * @param array $nodes AST nodes.
67 *
68 * @return bool
69 */
70 private function nodes_contain_drawer( array $nodes ): bool {
71 foreach ( $nodes as $node ) {
72 if ( ! is_array( $node ) ) {
73 continue;
74 }
75 if ( 'drawer' === ( $node['type'] ?? '' ) ) {
76 return true;
77 }
78 if ( ! empty( $node['children'] ) && is_array( $node['children'] ) && $this->nodes_contain_drawer( $node['children'] ) ) {
79 return true;
80 }
81 }
82
83 return false;
84 }
85
86 /**
87 * Format a value as centered plain text.
88 *
89 * Mirrors the rescue in Html_Thermal_Emitter::render_barcode_fallback(): when
90 * the symbol cannot be produced, the value itself is still readable.
91 *
92 * Control bytes are folded to spaces first. This is the one path that routes
93 * a barcode value into the text stream, and a barcode value is exactly where
94 * a stray tab, LF or CR turns up — Code 128 validation rejects them on the
95 * ESC/POS lane precisely because code set B cannot encode them, which sends
96 * them here. Emitted raw they would break the line the rescue is centering.
97 *
98 * @param string $value The value to print.
99 * @param int $columns The paper width in character columns.
100 *
101 * @return string The padded text, without a newline.
102 */
103 private function centered_text( string $value, int $columns ): string {
104 $text = Thermal_Text_Layout::normalize_text( $this->strip_control_bytes( $value ) );
105 // Preserve the barcode rescue's existing unscaled centering.
106 $pad = (int) floor( max( 0, $columns - Thermal_Text_Layout::display_width( $text ) ) / 2 );
107
108 return str_repeat( ' ', $pad ) . $text;
109 }
110
111 /**
112 * Replace control bytes with spaces so they cannot reach the print stream.
113 *
114 * @param string $value The value to clean.
115 *
116 * @return string The value with control bytes folded to spaces.
117 */
118 private function strip_control_bytes( string $value ): string {
119 $cleaned = preg_replace( '/[\x00-\x1f\x7f]/', ' ', $value );
120
121 return null === $cleaned ? $value : $cleaned;
122 }
123 }
124