PluginProbe
OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin / 1.1.9
OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin v1.1.9
1.1.9 1.1.8 1.1.7 1.1.6 1.1.5 1.1.4 1.1.3 1.1.2 1.1.1 1.1.0 1.0.1 1.0.0 0.9.8 0.9.7 0.9.6 0.9.4 0.9.5 0.9.3 0.9.2 0.9.1 0.9.0 0.8.9 0.8.8 0.8.7 0.8.6 All 33 releases
desktop-mode / includes / framework / app / html.php

html.php in OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin 1.1.9, at includes/framework/app/html.php

132 lines 3.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * OpenStation App Framework — template helpers.
4 *
5 * The four functions an `.os.php` view needs and nothing more:
6 *
7 * use function OpenStation\App\Html\{ esc, attr, json, tag };
8 *
9 * <os-badge tone="<?php echo esc( $tone ); ?>"><?php echo esc( $label ); ?></os-badge>
10 * <os-select<?php echo attr( array( 'value' => $id, 'disabled' => $off ) ); ?>>
11 * <os-histogram series="<?php echo json( $series ); ?>"></os-histogram>
12 *
13 * Host-agnostic on purpose — no `esc_html()` — so the same view
14 * renders on WordPress and on a bare PHP host. `esc()` and `json()`
15 * are registered as escaping functions in `phpcs.xml.dist`.
16 *
17 * @package OpenStation
18 */
19
20 namespace OpenStation\App\Html;
21
22 // Direct access, unless a standalone host is booting on bare PHP.
23 if ( ! defined( 'ABSPATH' ) ) {
24 defined( 'OPENSTATION_STANDALONE' ) || exit;
25 }
26
27 /**
28 * Escape text for an HTML text node or a quoted attribute.
29 *
30 * @param mixed $text Anything stringable.
31 * @return string
32 */
33 function esc( $text ) {
34 return htmlspecialchars( (string) $text, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8' );
35 }
36
37 /**
38 * Serialise a value as JSON, escaped for a quoted attribute.
39 *
40 * @param mixed $value JSON-serialisable value.
41 * @return string
42 */
43 function json( $value ) {
44 return esc( (string) json_encode( $value, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE ) );
45 }
46
47 /**
48 * Render an attribute list from an array, leading space included.
49 *
50 * `true` renders a bare boolean attribute, `false`/`null` render
51 * nothing, arrays and objects render as JSON, everything else is
52 * escaped. So `array( 'value' => 'x', 'open' => $is_open )` gives
53 * ` value="x" open` or ` value="x"`.
54 *
55 * @param array<string,mixed> $attrs Attribute map.
56 * @return string
57 */
58 function attr( array $attrs ) {
59 $out = '';
60 foreach ( $attrs as $name => $value ) {
61 if ( false === $value || null === $value ) {
62 continue;
63 }
64 $name = (string) $name;
65 if ( '' === $name || ! preg_match( '/^[a-zA-Z_:][-a-zA-Z0-9_:.]*$/', $name ) ) {
66 continue;
67 }
68 if ( true === $value ) {
69 $out .= ' ' . $name;
70 continue;
71 }
72 if ( is_array( $value ) || is_object( $value ) ) {
73 $out .= ' ' . $name . '="' . json( $value ) . '"';
74 continue;
75 }
76 $out .= ' ' . $name . '="' . esc( $value ) . '"';
77 }
78 return $out;
79 }
80
81 /**
82 * Render one element. `$inner` is HTML the caller already escaped
83 * (or built with these helpers) — pass `esc( $text )` for text.
84 *
85 * @param string $name Tag name.
86 * @param array<string,mixed> $attrs Attribute map, see {@see attr()}.
87 * @param string $inner Inner HTML. Ignored for void elements.
88 * @return string
89 */
90 function tag( $name, array $attrs = array(), $inner = '' ) {
91 static $void = array( 'area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input', 'link', 'meta', 'source', 'track', 'wbr' );
92
93 $name = strtolower( (string) preg_replace( '/[^a-zA-Z0-9-]/', '', (string) $name ) );
94 if ( '' === $name ) {
95 return '';
96 }
97 $open = '<' . $name . attr( $attrs ) . '>';
98 if ( in_array( $name, $void, true ) ) {
99 return $open;
100 }
101 return $open . (string) $inner . '</' . $name . '>';
102 }
103
104 /**
105 * Build a class attribute value from conditionals.
106 *
107 * `classes( 'row', array( 'is-open' => $open, 'is-busy' => $busy ) )`
108 * → `row is-open` when only `$open` is true.
109 *
110 * @param string|array ...$parts Class names, or `name => condition` maps.
111 * @return string
112 */
113 function classes( ...$parts ) {
114 $out = array();
115 foreach ( $parts as $part ) {
116 if ( is_array( $part ) ) {
117 foreach ( $part as $name => $condition ) {
118 if ( is_int( $name ) ) {
119 if ( '' !== (string) $condition ) {
120 $out[] = (string) $condition;
121 }
122 } elseif ( $condition ) {
123 $out[] = (string) $name;
124 }
125 }
126 } elseif ( '' !== (string) $part ) {
127 $out[] = (string) $part;
128 }
129 }
130 return implode( ' ', array_unique( $out ) );
131 }
132