PluginProbe
Gutenberg / 17.0.1
Gutenberg v17.0.1
24.0.0 23.9.1 23.9.0 23.8.0 23.7.2 23.7.1 23.7.0 23.6.1 23.6.2 23.6.0 23.5.3 23.5.2 23.5.1 23.5.0 23.4.0 23.3.2 23.3.1 23.3.0 23.2.0 23.2.1 23.2.2 23.1.1 23.1.0 23.0.1 12.6.0 All 403 releases
gutenberg / lib / experimental / interactivity-api / class-wp-directive-processor.php

class-wp-directive-processor.php in Gutenberg 17.0.1, at lib/experimental/interactivity-api/class-wp-directive-processor.php

229 lines 5.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * WP_Directive_Processor class
4 *
5 * @package Gutenberg
6 * @subpackage Interactivity API
7 */
8
9 if ( class_exists( 'WP_Directive_Processor' ) ) {
10 return;
11 }
12
13 /**
14 * This processor is built on top of the HTML Tag Processor and augments its
15 * capabilities to process the Interactivity API directives.
16 *
17 * IMPORTANT DISCLAIMER: This code is highly experimental and its only purpose
18 * is to provide a way to test the server-side rendering of the Interactivity
19 * API. Most of this code will be discarded once the HTML Processor is
20 * available. Please restrain from investing unnecessary time and effort trying
21 * to improve this code.
22 */
23 class WP_Directive_Processor extends Gutenberg_HTML_Tag_Processor_6_4 {
24
25 /**
26 * An array of root blocks.
27 *
28 * @var array
29 */
30 public static $root_blocks = array();
31
32 /**
33 * Add a root block to the list.
34 *
35 * @param array $block The block to add.
36 *
37 * @return void
38 */
39 public static function add_root_block( $block ) {
40 self::$root_blocks[] = md5( serialize( $block ) );
41 }
42
43 /**
44 * Check if block is a root block.
45 *
46 * @param array $block The block to check.
47 *
48 * @return bool True if block is a root block, false otherwise.
49 */
50 public static function is_root_block( $block ) {
51 return in_array( md5( serialize( $block ) ), self::$root_blocks, true );
52 }
53
54
55 /**
56 * Find the matching closing tag for an opening tag.
57 *
58 * When called while on an open tag, traverse the HTML until we find the
59 * matching closing tag, respecting any in-between content, including nested
60 * tags of the same name. Return false when called on a closing or void tag,
61 * or if no matching closing tag was found.
62 *
63 * @return bool Whether a matching closing tag was found.
64 */
65 public function next_balanced_closer() {
66 $depth = 0;
67
68 $tag_name = $this->get_tag();
69
70 if ( self::is_html_void_element( $tag_name ) ) {
71 return false;
72 }
73
74 while ( $this->next_tag(
75 array(
76 'tag_name' => $tag_name,
77 'tag_closers' => 'visit',
78 )
79 ) ) {
80 if ( ! $this->is_tag_closer() ) {
81 ++$depth;
82 continue;
83 }
84
85 if ( 0 === $depth ) {
86 return true;
87 }
88
89 --$depth;
90 }
91
92 return false;
93 }
94
95 /**
96 * Return the content between two balanced tags.
97 *
98 * When called on an opening tag, return the HTML content found between that
99 * opening tag and its matching closing tag.
100 *
101 * @return string The content between the current opening and its matching
102 * closing tag.
103 */
104 public function get_inner_html() {
105 $bookmarks = $this->get_balanced_tag_bookmarks();
106 if ( ! $bookmarks ) {
107 return false;
108 }
109 list( $start_name, $end_name ) = $bookmarks;
110
111 $start = $this->bookmarks[ $start_name ]->end + 1;
112 $end = $this->bookmarks[ $end_name ]->start;
113
114 $this->seek( $start_name ); // Return to original position.
115 $this->release_bookmark( $start_name );
116 $this->release_bookmark( $end_name );
117
118 return substr( $this->html, $start, $end - $start );
119 }
120
121 /**
122 * Set the content between two balanced tags.
123 *
124 * When called on an opening tag, set the HTML content found between that
125 * opening tag and its matching closing tag.
126 *
127 * @param string $new_html The string to replace the content between the
128 * matching tags with.
129 *
130 * @return bool Whether the content was successfully replaced.
131 */
132 public function set_inner_html( $new_html ) {
133 $this->get_updated_html(); // Apply potential previous updates.
134
135 $bookmarks = $this->get_balanced_tag_bookmarks();
136 if ( ! $bookmarks ) {
137 return false;
138 }
139 list( $start_name, $end_name ) = $bookmarks;
140
141 $start = $this->bookmarks[ $start_name ]->end + 1;
142 $end = $this->bookmarks[ $end_name ]->start;
143
144 $this->seek( $start_name ); // Return to original position.
145 $this->release_bookmark( $start_name );
146 $this->release_bookmark( $end_name );
147
148 $this->lexical_updates[] = new WP_HTML_Text_Replacement( $start, $end, $new_html );
149 return true;
150 }
151
152 /**
153 * Return a pair of bookmarks for the current opening tag and the matching
154 * closing tag.
155 *
156 * @return array|false A pair of bookmarks, or false if there's no matching
157 * closing tag.
158 */
159 public function get_balanced_tag_bookmarks() {
160 $i = 0;
161 while ( array_key_exists( 'start' . $i, $this->bookmarks ) ) {
162 ++$i;
163 }
164 $start_name = 'start' . $i;
165
166 $this->set_bookmark( $start_name );
167 if ( ! $this->next_balanced_closer() ) {
168 $this->release_bookmark( $start_name );
169 return false;
170 }
171
172 $i = 0;
173 while ( array_key_exists( 'end' . $i, $this->bookmarks ) ) {
174 ++$i;
175 }
176 $end_name = 'end' . $i;
177 $this->set_bookmark( $end_name );
178
179 return array( $start_name, $end_name );
180 }
181
182 /**
183 * Whether a given HTML element is void (e.g. <br>).
184 *
185 * @param string $tag_name The element in question.
186 * @return bool True if the element is void.
187 *
188 * @see https://html.spec.whatwg.org/#elements-2
189 */
190 public static function is_html_void_element( $tag_name ) {
191 switch ( $tag_name ) {
192 case 'AREA':
193 case 'BASE':
194 case 'BR':
195 case 'COL':
196 case 'EMBED':
197 case 'HR':
198 case 'IMG':
199 case 'INPUT':
200 case 'LINK':
201 case 'META':
202 case 'SOURCE':
203 case 'TRACK':
204 case 'WBR':
205 return true;
206
207 default:
208 return false;
209 }
210 }
211
212 /**
213 * Extract and return the directive type and the the part after the double
214 * hyphen from an attribute name (if present), in an array format.
215 *
216 * Examples:
217 *
218 * 'wp-island' => array( 'wp-island', null )
219 * 'wp-bind--src' => array( 'wp-bind', 'src' )
220 * 'wp-thing--and--thang' => array( 'wp-thing', 'and--thang' )
221 *
222 * @param string $name The attribute name.
223 * @return array The resulting array
224 */
225 public static function parse_attribute_name( $name ) {
226 return explode( '--', $name, 2 );
227 }
228 }
229