Skip to content

Commit 5a0d485

Browse files
committed
Highlight spans on hover
1 parent a68ce9e commit 5a0d485

File tree

4 files changed

+57
-54
lines changed

4 files changed

+57
-54
lines changed

html-api-debugger/interactivity.php

Lines changed: 8 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,6 @@ function generate_page( string $html, array $options ): string {
5252
'hasMutatedDom' => false,
5353
'html' => $html,
5454
'htmlapiResponse' => $htmlapi_response,
55-
'span' => false,
56-
'hoverSpan' => $htmlapi_response['html'],
5755

5856
'showClosers' => false,
5957
'showInvisible' => false,
@@ -131,13 +129,17 @@ class="html-api-debugger-container html-api-debugger--grid"
131129
<div class="full-width html-api-debugger--grid">
132130
<div>
133131
<h2>Interpreted by HTML API</h2>
134-
<div <?php wp_on_directive( 'click', 'handleSpanClick' ); ?>>
132+
<div
133+
<?php
134+
wp_on_directive( 'mouseover', 'handleSpanOver' );
135+
wp_on_directive( 'mouseleave', 'handleSpanClear' );
136+
?>
137+
>
135138
<pre class="error-holder" data-wp-bind--hidden="!state.htmlapiResponse.error" data-wp-text="state.htmlapiResponse.error"></pre>
136139
<div data-wp-bind--hidden="state.htmlapiResponse.error">
137140
<ul id="html_api_result_holder" data-wp-ignore></ul>
138141
</div>
139142
</div>
140-
<p>Click a node above to see its span details below.</p>
141143
</div>
142144
<div>
143145
<h2>Interpreted from DOM</h2>
@@ -166,20 +168,8 @@ class="html-api-debugger-container html-api-debugger--grid"
166168
</div>
167169

168170
<div>
169-
<div data-wp-bind--hidden="state.span">
170-
<h2>Processed HTML</h2>
171-
<pre class="html-text" data-wp-text="state.hoverSpan"></pre>
172-
</div>
173-
174-
<div data-wp-bind--hidden="!state.span">
175-
<h2>Processed HTML selected span</h2>
176-
<button <?php wp_on_directive( 'click', 'clearSpan' ); ?> type="button">Clear span selection 🧹</button>
177-
<div class="htmlSpanContainer">
178-
<pre class="html-text html-span" data-wp-text="state.hoverSpanSplit.0"></pre>
179-
<pre class="html-text html-span html selected span" data-wp-text="state.hoverSpanSplit.1"></pre>
180-
<pre class="html-text html-span" data-wp-text="state.hoverSpanSplit.2"></pre>
181-
</div>
182-
</div>
171+
<h2>Processed HTML</h2>
172+
<pre class="html-text" id="processed-html" data-wp-ignore><?php echo esc_html( $html ); ?></pre>
183173
</div>
184174

185175
<div>

html-api-debugger/readme.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,3 +87,4 @@ Add a page to wp-admin for debugging the HTML API.
8787
* Register script modules unconditionally.
8888

8989
= 1.8 =
90+
* Highlight spans in HTML input on hover.

html-api-debugger/style.css

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,12 @@
7878
color: white;
7979
}
8080
}
81+
82+
.highlight-span {
83+
box-shadow:
84+
0 0 2px 1px hotpink,
85+
inset 0 0 2px 1px hotpink;
86+
}
8187
}
8288

8389
#rendered_iframe {
@@ -91,19 +97,6 @@
9197
text-wrap: pretty;
9298
}
9399

94-
.htmlSpanContainer {
95-
display: flex;
96-
gap: 0.2em;
97-
}
98-
99-
.html-span {
100-
flex: 1 1 0;
101-
}
102-
103-
.html-span:nth-child(2) {
104-
box-shadow: 3px 3px 3px hotpink;
105-
}
106-
107100
#html_api_result_holder,
108101
#dom_tree {
109102
border: inset 1px;

html-api-debugger/view.js

Lines changed: 42 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ let mutationObserver = null;
7676
* @property {boolean} hasMutatedDom
7777
* @property {HTMLAPISpan|false} span
7878
* @property {string} hoverSpan
79-
* @property {readonly []|readonly [string,string,string]} hoverSpanSplit
79+
* @property {(span:HTMLAPISpan) => readonly [string,string,string]} hoverSpanSplit
8080
*/
8181

8282
/**
@@ -200,16 +200,17 @@ const store = createStore(NS, {
200200
return store.state.showInvisible ? replaceInvisible(html) : html;
201201
},
202202

203-
get hoverSpanSplit() {
203+
/** @param {HTMLAPISpan} span */
204+
hoverSpanSplit(span) {
204205
/** @type {string | undefined} */
205206
const html = store.state.htmlapiResponse.html;
206-
if (!html || !store.state.span) {
207-
return /** @type {const} */ ([]);
207+
if (!html) {
208+
return /** @type {const} */ (['', '', '']);
208209
}
209210
const buf = new TextEncoder().encode(html);
210211
const decoder = new TextDecoder();
211212

212-
const { start: spanStart, length } = store.state.span;
213+
const { start: spanStart, length } = span;
213214
const spanEnd = spanStart + length;
214215
const split = /** @type {const} */ ([
215216
decoder.decode(buf.slice(0, spanStart)),
@@ -223,6 +224,42 @@ const store = createStore(NS, {
223224
: split;
224225
},
225226
},
227+
228+
/** @param {MouseEvent} e */
229+
handleSpanClear(e) {
230+
/** @type {HTMLElement} */ (
231+
document.getElementById('processed-html')
232+
).textContent = store.state.hoverSpan;
233+
},
234+
235+
/** @param {MouseEvent} e */
236+
handleSpanOver(e) {
237+
const t = /** @type {HTMLElement} */ (e.target);
238+
const { spanStart, spanLength } = t.dataset;
239+
if (!t || !spanStart || !spanLength) {
240+
return;
241+
}
242+
243+
console.log('t: %o, ct: %o', e.target, e.currentTarget);
244+
// @ts-expect-error 3-tuple to 3-tuple
245+
const [before, current, after] = /** @type {readonly [Text,Text,Text]} */ (
246+
store.state
247+
.hoverSpanSplit({
248+
start: Number(spanStart),
249+
length: Number(spanLength),
250+
})
251+
.map((text) => document.createTextNode(text))
252+
);
253+
const highlightCurrent = document.createElement('span');
254+
highlightCurrent.className = 'highlight-span';
255+
highlightCurrent.appendChild(current);
256+
257+
const el = /** @type {HTMLElement} */ (
258+
document.getElementById('processed-html')
259+
);
260+
el.replaceChildren(before, highlightCurrent, after);
261+
},
262+
226263
run() {
227264
// The HTML parser will replace null bytes from the HTML.
228265
// Force print them if we have null bytes.
@@ -292,10 +329,6 @@ const store = createStore(NS, {
292329
);
293330
},
294331

295-
clearSpan() {
296-
store.state.span = false;
297-
},
298-
299332
/** @param {InputEvent} e */
300333
handleInput: function* (e) {
301334
const val = /** @type {HTMLTextAreaElement} */ (e.target).value;
@@ -340,20 +373,6 @@ const store = createStore(NS, {
340373
}
341374
},
342375

343-
/** @param {Event} e */
344-
handleSpanClick(e) {
345-
const t = e.target;
346-
if (t && t instanceof HTMLElement) {
347-
/** @type {HTMLElement|null} */
348-
const spanEl = t.closest('[data-span-start]');
349-
if (spanEl) {
350-
const start = Number(spanEl.dataset['spanStart']);
351-
const length = Number(spanEl.dataset['spanLength']);
352-
store.state.span = { start, length };
353-
}
354-
}
355-
},
356-
357376
handleShowInvisibleClick: getToggleHandler('showInvisible'),
358377
handleShowClosersClick: getToggleHandler('showClosers'),
359378
handleShowVirtualClick: getToggleHandler('showVirtual'),

0 commit comments

Comments
 (0)