PluginProbe
OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin / 1.1.8
OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin v1.1.8
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 / window-chrome.php

window-chrome.php in OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin 1.1.8, at includes/window-chrome.php

947 lines 25.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Window-chrome customization framework — server-side registration APIs.
4 *
5 * Mirrors the commands / settings-tabs / title-bar-buttons registration
6 * pattern across four surfaces:
7 *
8 * - **Themes** (Layer 1) — per-window CSS-variable maps.
9 * `openstation_register_window_theme_script()` /
10 * `openstation_register_window_theme()`.
11 *
12 * - **Controls** (Layer 2) — title-bar buttons (close / minimize /
13 * maximize plus plugin custom controls).
14 * `openstation_register_window_control_script()` /
15 * `openstation_register_window_control()`.
16 *
17 * - **Slots** (Layer 3) — named title-bar regions plugins can
18 * replace (icon, title, before-controls, …).
19 * `openstation_register_window_slot_script()` /
20 * `openstation_register_window_slot()`.
21 *
22 * - **Chrome** (Layer 4, Experimental) — full title-bar render
23 * replacement.
24 * `openstation_register_window_chrome_script()` /
25 * `openstation_register_window_chrome()`.
26 *
27 * Each surface contributes a `serverWindow*Scripts` and (optionally)
28 * `serverWindow*` array to the shell payload, consumed by the matching
29 * sync module under `src/window-chrome/{themes,controls,slots,chrome}/server-sync.ts`.
30 *
31 * @package OpenStation
32 */
33
34 defined( 'ABSPATH' ) || exit;
35
36 /*
37 ============================================================
38 * Layer 1 — Themes
39 * ============================================================
40 */
41
42 /**
43 * Declare a WP-registered script handle as a window-theme provider.
44 *
45 * The script's JS calls `wp.os.registerWindowTheme( { id, tokens,
46 * match, owner } )` as usual. Plugins that pass `owner` matching this
47 * handle get live unregister on deactivation.
48 *
49 * @param string $handle WP-registered script handle.
50 * @return true|WP_Error `true` on success; `WP_Error` on validation failure.
51 */
52 function openstation_register_window_theme_script( $handle ) {
53 $handle = (string) $handle;
54 if ( '' === $handle ) {
55 return openstation_registration_error(
56 'openstation_missing_handle',
57 __( 'Window theme script registration requires a non-empty script handle.', 'desktop-mode' )
58 );
59 }
60
61 openstation_window_theme_script_registry( $handle, true );
62
63 /**
64 * Fires after a desktop window-theme script handle is registered.
65 *
66 * @param string $handle The registered script handle.
67 */
68 do_action( 'openstation_window_theme_script_registered', $handle );
69
70 return true;
71 }
72
73 /**
74 * Declare a window theme server-side. Optional companion to
75 * `openstation_register_window_theme_script()` for plugins that want
76 * to ship a tokens map without writing JS — designers can hand off
77 * a single PHP-array of CSS variables and call it done.
78 *
79 * @param array $args {
80 * @type string $id Unique theme id (`vendor/sub-id`). Required.
81 * @type string $label Human-readable label. Default empty.
82 * @type array $tokens CSS-variable map (keys must start with `--`). Required.
83 * @type int $priority Override priority (higher wins). Default 100.
84 * @type string $script Optional script handle (also registers it).
85 * }
86 * @return true|WP_Error
87 */
88 function openstation_register_window_theme( $args = array() ) {
89 $defaults = array(
90 'id' => '',
91 'label' => '',
92 'tokens' => array(),
93 'priority' => 100,
94 'script' => '',
95 );
96 $args = wp_parse_args( $args, $defaults );
97
98 $id = (string) $args['id'];
99 if ( '' === $id ) {
100 return openstation_registration_error(
101 'openstation_missing_id',
102 __( 'Window theme registration requires a non-empty `id`.', 'desktop-mode' )
103 );
104 }
105 if ( ! is_array( $args['tokens'] ) || empty( $args['tokens'] ) ) {
106 return openstation_registration_error(
107 'openstation_missing_tokens',
108 __( 'Window theme registration requires a non-empty `tokens` map.', 'desktop-mode' ),
109 array( 'id' => $id )
110 );
111 }
112 $tokens = array();
113 foreach ( $args['tokens'] as $key => $value ) {
114 $key = (string) $key;
115 if ( '' === $key || 0 !== strpos( $key, '--' ) ) {
116 return openstation_registration_error(
117 'openstation_invalid_token',
118 __( 'Window theme tokens must use CSS custom-property keys (start with "--").', 'desktop-mode' ),
119 array(
120 'id' => $id,
121 'key' => $key,
122 )
123 );
124 }
125 $tokens[ $key ] = (string) $value;
126 }
127
128 $entry = array(
129 'id' => $id,
130 'label' => (string) $args['label'],
131 'tokens' => $tokens,
132 'priority' => (int) $args['priority'],
133 'script' => (string) $args['script'],
134 );
135 openstation_window_theme_registry( $id, $entry );
136
137 if ( '' !== $entry['script'] ) {
138 openstation_window_theme_script_registry( $entry['script'], true );
139 }
140
141 /**
142 * Fires after a desktop window-theme is successfully registered.
143 *
144 * @param string $id The theme id.
145 * @param array $entry The stored registry entry.
146 */
147 do_action( 'openstation_window_theme_registered', $id, $entry );
148
149 return true;
150 }
151
152 /**
153 * Internal module-level registry for theme script handles.
154 *
155 * @internal
156 *
157 * @param string $handle Script handle to read or write.
158 * @param bool|null $value Pass `true` to register; `null` to read only.
159 * @return array|bool When called with no args returns the full store.
160 */
161 function openstation_window_theme_script_registry( $handle = '', $value = null ) {
162 static $store = array();
163
164 if ( '__flush__' === (string) $handle ) {
165 $store = array();
166 return array();
167 }
168 if ( '' === (string) $handle ) {
169 return $store;
170 }
171 if ( null !== $value ) {
172 $store[ (string) $handle ] = (bool) $value;
173 }
174 return isset( $store[ (string) $handle ] ) ? $store[ (string) $handle ] : false;
175 }
176
177 /** Flush the theme-script registry. Tests only. */
178 function openstation_flush_window_theme_script_registry() {
179 openstation_window_theme_script_registry( '__flush__' );
180 }
181
182 /**
183 * Internal module-level registry for window themes.
184 *
185 * @internal
186 *
187 * @param string $id Theme id to read or write.
188 * @param array|null $entry Entry to store, or `null` to read.
189 * @return array|null
190 */
191 function openstation_window_theme_registry( $id = '', $entry = null ) {
192 static $store = array();
193
194 if ( '__flush__' === (string) $id ) {
195 $store = array();
196 return array();
197 }
198 if ( '' === (string) $id ) {
199 return $store;
200 }
201 if ( null !== $entry ) {
202 $store[ (string) $id ] = $entry;
203 }
204 return isset( $store[ (string) $id ] ) ? $store[ (string) $id ] : null;
205 }
206
207 /** Flush the theme registry. Tests only. */
208 function openstation_flush_window_theme_registry() {
209 openstation_window_theme_registry( '__flush__' );
210 }
211
212 /**
213 * Build the theme-script payload. Same shape as
214 * `openstation_build_desktop_command_scripts_payload()`.
215 *
216 * @return array[] List of `{ handle, scriptUrl }` entries.
217 */
218 function openstation_build_window_theme_scripts_payload() {
219 $registry = openstation_window_theme_script_registry();
220 if ( ! is_array( $registry ) || empty( $registry ) ) {
221 return array();
222 }
223
224 $out = array();
225 $seen = array();
226 foreach ( $registry as $handle => $active ) {
227 if ( ! $active || isset( $seen[ $handle ] ) ) {
228 continue;
229 }
230 $payload = openstation_resolve_script_payload( $handle );
231 if ( '' === $payload['url'] ) {
232 openstation_warn_unresolvable_script_handle(
233 'openstation_register_window_theme_script',
234 'Window theme',
235 (string) $handle
236 );
237 continue;
238 }
239 $out[] = array(
240 'handle' => (string) $handle,
241 'scriptUrl' => $payload['url'],
242 'scriptBefore' => $payload['before'],
243 'scriptAfter' => $payload['after'],
244 'scriptL10n' => $payload['l10n'],
245 'scriptTranslations' => $payload['translations'],
246 );
247 $seen[ $handle ] = true;
248 }
249 return $out;
250 }
251
252 /**
253 * Build the theme-metadata payload. Resolves the optional companion
254 * script handle for each entry.
255 *
256 * @return array[]
257 */
258 function openstation_build_window_themes_payload() {
259 $registry = openstation_window_theme_registry();
260 if ( ! is_array( $registry ) || empty( $registry ) ) {
261 return array();
262 }
263
264 $out = array();
265 foreach ( $registry as $entry ) {
266 $handle = (string) $entry['script'];
267 $payload = '' !== $handle
268 ? openstation_resolve_script_payload( $handle )
269 : array(
270 'url' => '',
271 'before' => array(),
272 'after' => array(),
273 'l10n' => array(),
274 'translations' => '',
275 );
276 $out[] = array(
277 'id' => (string) $entry['id'],
278 'label' => (string) $entry['label'],
279 'tokens' => (array) $entry['tokens'],
280 'priority' => (int) $entry['priority'],
281 'scriptUrl' => $payload['url'],
282 'scriptHandle' => $handle,
283 'scriptBefore' => $payload['before'],
284 'scriptAfter' => $payload['after'],
285 'scriptL10n' => $payload['l10n'],
286 'scriptTranslations' => $payload['translations'],
287 );
288 }
289 return $out;
290 }
291
292 /*
293 ============================================================
294 * Layer 2 — Controls
295 * ============================================================
296 */
297
298 /**
299 * Declare a WP-registered script handle as a window-control provider.
300 *
301 * @param string $handle WP-registered script handle.
302 * @return true|WP_Error
303 */
304 function openstation_register_window_control_script( $handle ) {
305 $handle = (string) $handle;
306 if ( '' === $handle ) {
307 return openstation_registration_error(
308 'openstation_missing_handle',
309 __( 'Window control script registration requires a non-empty script handle.', 'desktop-mode' )
310 );
311 }
312
313 openstation_window_control_script_registry( $handle, true );
314
315 /**
316 * Fires after a window-control script handle is registered.
317 *
318 * @param string $handle The registered script handle.
319 */
320 do_action( 'openstation_window_control_script_registered', $handle );
321
322 return true;
323 }
324
325 /**
326 * Declare a window control server-side. The control's `onClick` /
327 * `render` callback always lives JS-side.
328 *
329 * @param array $args {
330 * @type string $id Required, `vendor/sub-id`.
331 * @type string $label Required.
332 * @type string $icon Dashicons class / built-in key / SVG.
333 * @type string $placement `'left' | 'right' | 'controls'`. Default `'left'`.
334 * @type int $order Sort within placement. Default 100.
335 * @type string $script Optional companion script handle.
336 * }
337 * @return true|WP_Error
338 */
339 function openstation_register_window_control( $args = array() ) {
340 $defaults = array(
341 'id' => '',
342 'label' => '',
343 'icon' => '',
344 'placement' => 'left',
345 'order' => 100,
346 'script' => '',
347 );
348 $args = wp_parse_args( $args, $defaults );
349
350 $id = (string) $args['id'];
351 if ( '' === $id ) {
352 return openstation_registration_error(
353 'openstation_missing_id',
354 __( 'Window control registration requires a non-empty `id`.', 'desktop-mode' )
355 );
356 }
357 if ( '' === (string) $args['label'] ) {
358 return openstation_registration_error(
359 'openstation_missing_label',
360 __( 'Window control registration requires a non-empty `label`.', 'desktop-mode' ),
361 array( 'id' => $id )
362 );
363 }
364 $placement = (string) $args['placement'];
365 if ( ! in_array( $placement, array( 'left', 'right', 'controls' ), true ) ) {
366 return openstation_registration_error(
367 'openstation_invalid_placement',
368 __( 'Window control `placement` must be one of "left", "right", "controls".', 'desktop-mode' ),
369 array(
370 'id' => $id,
371 'placement' => $placement,
372 )
373 );
374 }
375
376 $entry = array(
377 'id' => $id,
378 'label' => (string) $args['label'],
379 'icon' => (string) $args['icon'],
380 'placement' => $placement,
381 'order' => (int) $args['order'],
382 'script' => (string) $args['script'],
383 );
384 openstation_window_control_registry( $id, $entry );
385
386 if ( '' !== $entry['script'] ) {
387 openstation_window_control_script_registry( $entry['script'], true );
388 }
389
390 /**
391 * Fires after a window-control is successfully registered.
392 *
393 * @param string $id The control id.
394 * @param array $entry The stored registry entry.
395 */
396 do_action( 'openstation_window_control_registered', $id, $entry );
397
398 return true;
399 }
400
401 /** @internal */
402 function openstation_window_control_script_registry( $handle = '', $value = null ) {
403 static $store = array();
404
405 if ( '__flush__' === (string) $handle ) {
406 $store = array();
407 return array();
408 }
409 if ( '' === (string) $handle ) {
410 return $store;
411 }
412 if ( null !== $value ) {
413 $store[ (string) $handle ] = (bool) $value;
414 }
415 return isset( $store[ (string) $handle ] ) ? $store[ (string) $handle ] : false;
416 }
417
418 /** Tests only. */
419 function openstation_flush_window_control_script_registry() {
420 openstation_window_control_script_registry( '__flush__' );
421 }
422
423 /** @internal */
424 function openstation_window_control_registry( $id = '', $entry = null ) {
425 static $store = array();
426
427 if ( '__flush__' === (string) $id ) {
428 $store = array();
429 return array();
430 }
431 if ( '' === (string) $id ) {
432 return $store;
433 }
434 if ( null !== $entry ) {
435 $store[ (string) $id ] = $entry;
436 }
437 return isset( $store[ (string) $id ] ) ? $store[ (string) $id ] : null;
438 }
439
440 /** Tests only. */
441 function openstation_flush_window_control_registry() {
442 openstation_window_control_registry( '__flush__' );
443 }
444
445 /**
446 * @return array[] List of `{ handle, scriptUrl }` entries.
447 */
448 function openstation_build_window_control_scripts_payload() {
449 $registry = openstation_window_control_script_registry();
450 if ( ! is_array( $registry ) || empty( $registry ) ) {
451 return array();
452 }
453
454 $out = array();
455 $seen = array();
456 foreach ( $registry as $handle => $active ) {
457 if ( ! $active || isset( $seen[ $handle ] ) ) {
458 continue;
459 }
460 $payload = openstation_resolve_script_payload( $handle );
461 if ( '' === $payload['url'] ) {
462 openstation_warn_unresolvable_script_handle(
463 'openstation_register_window_control_script',
464 'Window control',
465 (string) $handle
466 );
467 continue;
468 }
469 $out[] = array(
470 'handle' => (string) $handle,
471 'scriptUrl' => $payload['url'],
472 'scriptBefore' => $payload['before'],
473 'scriptAfter' => $payload['after'],
474 'scriptL10n' => $payload['l10n'],
475 'scriptTranslations' => $payload['translations'],
476 );
477 $seen[ $handle ] = true;
478 }
479 return $out;
480 }
481
482 /**
483 * @return array[]
484 */
485 function openstation_build_window_controls_payload() {
486 $registry = openstation_window_control_registry();
487 if ( ! is_array( $registry ) || empty( $registry ) ) {
488 return array();
489 }
490
491 $out = array();
492 foreach ( $registry as $entry ) {
493 $handle = (string) $entry['script'];
494 $payload = '' !== $handle
495 ? openstation_resolve_script_payload( $handle )
496 : array(
497 'url' => '',
498 'before' => array(),
499 'after' => array(),
500 'l10n' => array(),
501 'translations' => '',
502 );
503 $out[] = array(
504 'id' => (string) $entry['id'],
505 'label' => (string) $entry['label'],
506 'icon' => (string) $entry['icon'],
507 'placement' => (string) $entry['placement'],
508 'order' => (int) $entry['order'],
509 'scriptUrl' => $payload['url'],
510 'scriptHandle' => $handle,
511 'scriptBefore' => $payload['before'],
512 'scriptAfter' => $payload['after'],
513 'scriptL10n' => $payload['l10n'],
514 'scriptTranslations' => $payload['translations'],
515 );
516 }
517 return $out;
518 }
519
520 /*
521 ============================================================
522 * Layer 3 — Slots
523 * ============================================================
524 */
525
526 /**
527 * Canonical slot names. Mirrors the `WindowSlotName` TypeScript
528 * union in `src/types.ts`.
529 *
530 * @return string[]
531 */
532 function openstation_window_slot_names() {
533 return array(
534 'before-titlebar',
535 'before-icon',
536 'icon',
537 'title',
538 'after-title',
539 'before-controls',
540 'controls',
541 'after-controls',
542 'after-titlebar',
543 );
544 }
545
546 /**
547 * @param string $handle WP-registered script handle.
548 * @return true|WP_Error
549 */
550 function openstation_register_window_slot_script( $handle ) {
551 $handle = (string) $handle;
552 if ( '' === $handle ) {
553 return openstation_registration_error(
554 'openstation_missing_handle',
555 __( 'Window slot script registration requires a non-empty script handle.', 'desktop-mode' )
556 );
557 }
558
559 openstation_window_slot_script_registry( $handle, true );
560
561 /**
562 * Fires after a window-slot script handle is registered.
563 *
564 * @param string $handle The registered script handle.
565 */
566 do_action( 'openstation_window_slot_script_registered', $handle );
567
568 return true;
569 }
570
571 /**
572 * @param array $args {
573 * @type string $id Required.
574 * @type string $slot Required, one of {@see openstation_window_slot_names()}.
575 * @type int $order Default 100.
576 * @type string $script Optional script handle.
577 * }
578 * @return true|WP_Error
579 */
580 function openstation_register_window_slot( $args = array() ) {
581 $defaults = array(
582 'id' => '',
583 'slot' => '',
584 'order' => 100,
585 'script' => '',
586 );
587 $args = wp_parse_args( $args, $defaults );
588
589 $id = (string) $args['id'];
590 if ( '' === $id ) {
591 return openstation_registration_error(
592 'openstation_missing_id',
593 __( 'Window slot registration requires a non-empty `id`.', 'desktop-mode' )
594 );
595 }
596 $slot = (string) $args['slot'];
597 if ( ! in_array( $slot, openstation_window_slot_names(), true ) ) {
598 return openstation_registration_error(
599 'openstation_invalid_slot',
600 __( 'Window slot registration requires a known `slot` name.', 'desktop-mode' ),
601 array(
602 'id' => $id,
603 'slot' => $slot,
604 )
605 );
606 }
607
608 $entry = array(
609 'id' => $id,
610 'slot' => $slot,
611 'order' => (int) $args['order'],
612 'script' => (string) $args['script'],
613 );
614 openstation_window_slot_registry( $id, $entry );
615
616 if ( '' !== $entry['script'] ) {
617 openstation_window_slot_script_registry( $entry['script'], true );
618 }
619
620 /**
621 * Fires after a window-slot is successfully registered.
622 *
623 * @param string $id The slot-renderer id.
624 * @param array $entry The stored registry entry.
625 */
626 do_action( 'openstation_window_slot_registered', $id, $entry );
627
628 return true;
629 }
630
631 /** @internal */
632 function openstation_window_slot_script_registry( $handle = '', $value = null ) {
633 static $store = array();
634
635 if ( '__flush__' === (string) $handle ) {
636 $store = array();
637 return array();
638 }
639 if ( '' === (string) $handle ) {
640 return $store;
641 }
642 if ( null !== $value ) {
643 $store[ (string) $handle ] = (bool) $value;
644 }
645 return isset( $store[ (string) $handle ] ) ? $store[ (string) $handle ] : false;
646 }
647
648 /** Tests only. */
649 function openstation_flush_window_slot_script_registry() {
650 openstation_window_slot_script_registry( '__flush__' );
651 }
652
653 /** @internal */
654 function openstation_window_slot_registry( $id = '', $entry = null ) {
655 static $store = array();
656
657 if ( '__flush__' === (string) $id ) {
658 $store = array();
659 return array();
660 }
661 if ( '' === (string) $id ) {
662 return $store;
663 }
664 if ( null !== $entry ) {
665 $store[ (string) $id ] = $entry;
666 }
667 return isset( $store[ (string) $id ] ) ? $store[ (string) $id ] : null;
668 }
669
670 /** Tests only. */
671 function openstation_flush_window_slot_registry() {
672 openstation_window_slot_registry( '__flush__' );
673 }
674
675 /**
676 * @return array[] List of `{ handle, scriptUrl }` entries.
677 */
678 function openstation_build_window_slot_scripts_payload() {
679 $registry = openstation_window_slot_script_registry();
680 if ( ! is_array( $registry ) || empty( $registry ) ) {
681 return array();
682 }
683
684 $out = array();
685 $seen = array();
686 foreach ( $registry as $handle => $active ) {
687 if ( ! $active || isset( $seen[ $handle ] ) ) {
688 continue;
689 }
690 $payload = openstation_resolve_script_payload( $handle );
691 if ( '' === $payload['url'] ) {
692 openstation_warn_unresolvable_script_handle(
693 'openstation_register_window_slot_script',
694 'Window slot',
695 (string) $handle
696 );
697 continue;
698 }
699 $out[] = array(
700 'handle' => (string) $handle,
701 'scriptUrl' => $payload['url'],
702 'scriptBefore' => $payload['before'],
703 'scriptAfter' => $payload['after'],
704 'scriptL10n' => $payload['l10n'],
705 'scriptTranslations' => $payload['translations'],
706 );
707 $seen[ $handle ] = true;
708 }
709 return $out;
710 }
711
712 /**
713 * @return array[]
714 */
715 function openstation_build_window_slots_payload() {
716 $registry = openstation_window_slot_registry();
717 if ( ! is_array( $registry ) || empty( $registry ) ) {
718 return array();
719 }
720
721 $out = array();
722 foreach ( $registry as $entry ) {
723 $handle = (string) $entry['script'];
724 $payload = '' !== $handle
725 ? openstation_resolve_script_payload( $handle )
726 : array(
727 'url' => '',
728 'before' => array(),
729 'after' => array(),
730 'l10n' => array(),
731 'translations' => '',
732 );
733 $out[] = array(
734 'id' => (string) $entry['id'],
735 'slot' => (string) $entry['slot'],
736 'order' => (int) $entry['order'],
737 'scriptUrl' => $payload['url'],
738 'scriptHandle' => $handle,
739 'scriptBefore' => $payload['before'],
740 'scriptAfter' => $payload['after'],
741 'scriptL10n' => $payload['l10n'],
742 'scriptTranslations' => $payload['translations'],
743 );
744 }
745 return $out;
746 }
747
748 /*
749 ============================================================
750 * Layer 4 — Custom chrome (Experimental)
751 * ============================================================
752 */
753
754 /**
755 * Declare a WP-registered script handle as a window-chrome provider.
756 *
757 * **Experimental** — chrome render contract may change.
758 *
759 * @param string $handle WP-registered script handle.
760 * @return true|WP_Error
761 */
762 function openstation_register_window_chrome_script( $handle ) {
763 $handle = (string) $handle;
764 if ( '' === $handle ) {
765 return openstation_registration_error(
766 'openstation_missing_handle',
767 __( 'Window chrome script registration requires a non-empty script handle.', 'desktop-mode' )
768 );
769 }
770
771 openstation_window_chrome_script_registry( $handle, true );
772
773 /**
774 * Fires after a window-chrome script handle is registered.
775 *
776 * @param string $handle The registered script handle.
777 */
778 do_action( 'openstation_window_chrome_script_registered', $handle );
779
780 return true;
781 }
782
783 /**
784 * Declare a custom chrome server-side. **Experimental** — chrome
785 * render contract may change.
786 *
787 * @param array $args {
788 * @type string $id Required.
789 * @type string $label Default empty.
790 * @type string $script Optional script handle.
791 * }
792 * @return true|WP_Error
793 */
794 function openstation_register_window_chrome( $args = array() ) {
795 $defaults = array(
796 'id' => '',
797 'label' => '',
798 'script' => '',
799 );
800 $args = wp_parse_args( $args, $defaults );
801
802 $id = (string) $args['id'];
803 if ( '' === $id ) {
804 return openstation_registration_error(
805 'openstation_missing_id',
806 __( 'Window chrome registration requires a non-empty `id`.', 'desktop-mode' )
807 );
808 }
809
810 $entry = array(
811 'id' => $id,
812 'label' => (string) $args['label'],
813 'script' => (string) $args['script'],
814 );
815 openstation_window_chrome_registry( $id, $entry );
816
817 if ( '' !== $entry['script'] ) {
818 openstation_window_chrome_script_registry( $entry['script'], true );
819 }
820
821 /**
822 * Fires after a window-chrome is successfully registered.
823 *
824 * @param string $id The chrome id.
825 * @param array $entry The stored registry entry.
826 */
827 do_action( 'openstation_window_chrome_registered', $id, $entry );
828
829 return true;
830 }
831
832 /** @internal */
833 function openstation_window_chrome_script_registry( $handle = '', $value = null ) {
834 static $store = array();
835
836 if ( '__flush__' === (string) $handle ) {
837 $store = array();
838 return array();
839 }
840 if ( '' === (string) $handle ) {
841 return $store;
842 }
843 if ( null !== $value ) {
844 $store[ (string) $handle ] = (bool) $value;
845 }
846 return isset( $store[ (string) $handle ] ) ? $store[ (string) $handle ] : false;
847 }
848
849 /** Tests only. */
850 function openstation_flush_window_chrome_script_registry() {
851 openstation_window_chrome_script_registry( '__flush__' );
852 }
853
854 /** @internal */
855 function openstation_window_chrome_registry( $id = '', $entry = null ) {
856 static $store = array();
857
858 if ( '__flush__' === (string) $id ) {
859 $store = array();
860 return array();
861 }
862 if ( '' === (string) $id ) {
863 return $store;
864 }
865 if ( null !== $entry ) {
866 $store[ (string) $id ] = $entry;
867 }
868 return isset( $store[ (string) $id ] ) ? $store[ (string) $id ] : null;
869 }
870
871 /** Tests only. */
872 function openstation_flush_window_chrome_registry() {
873 openstation_window_chrome_registry( '__flush__' );
874 }
875
876 /**
877 * @return array[] List of `{ handle, scriptUrl }` entries.
878 */
879 function openstation_build_window_chrome_scripts_payload() {
880 $registry = openstation_window_chrome_script_registry();
881 if ( ! is_array( $registry ) || empty( $registry ) ) {
882 return array();
883 }
884
885 $out = array();
886 $seen = array();
887 foreach ( $registry as $handle => $active ) {
888 if ( ! $active || isset( $seen[ $handle ] ) ) {
889 continue;
890 }
891 $payload = openstation_resolve_script_payload( $handle );
892 if ( '' === $payload['url'] ) {
893 openstation_warn_unresolvable_script_handle(
894 'openstation_register_window_chrome_script',
895 'Window chrome',
896 (string) $handle
897 );
898 continue;
899 }
900 $out[] = array(
901 'handle' => (string) $handle,
902 'scriptUrl' => $payload['url'],
903 'scriptBefore' => $payload['before'],
904 'scriptAfter' => $payload['after'],
905 'scriptL10n' => $payload['l10n'],
906 'scriptTranslations' => $payload['translations'],
907 );
908 $seen[ $handle ] = true;
909 }
910 return $out;
911 }
912
913 /**
914 * @return array[]
915 */
916 function openstation_build_window_chromes_payload() {
917 $registry = openstation_window_chrome_registry();
918 if ( ! is_array( $registry ) || empty( $registry ) ) {
919 return array();
920 }
921
922 $out = array();
923 foreach ( $registry as $entry ) {
924 $handle = (string) $entry['script'];
925 $payload = '' !== $handle
926 ? openstation_resolve_script_payload( $handle )
927 : array(
928 'url' => '',
929 'before' => array(),
930 'after' => array(),
931 'l10n' => array(),
932 'translations' => '',
933 );
934 $out[] = array(
935 'id' => (string) $entry['id'],
936 'label' => (string) $entry['label'],
937 'scriptUrl' => $payload['url'],
938 'scriptHandle' => $handle,
939 'scriptBefore' => $payload['before'],
940 'scriptAfter' => $payload['after'],
941 'scriptL10n' => $payload['l10n'],
942 'scriptTranslations' => $payload['translations'],
943 );
944 }
945 return $out;
946 }
947