| @@ -29,10 +29,9 @@ | ||
| 29 | 29 | * |
| 30 | 30 | * Reported to Elegant Themes. Remove this file when Divi ships |
| 31 | 31 | * the fix upstream. |
| 32 | 32 | * |
| 33 | - * @since 0.18.x | |
| 34 | - * @package WP_Desktop_Mode\Compat | |
| 33 | + * @package OpenStation\Compat | |
| 35 | 34 | */ |
| 36 | 35 | |
| 37 | 36 | defined( 'ABSPATH' ) || exit; |
| 38 | 37 | |
| @@ -82,13 +81,11 @@ | ||
| 82 | 81 | * |
| 83 | 82 | * Reported to Elegant Themes. Remove this file when Divi ships |
| 84 | 83 | * the fix upstream. |
| 85 | 84 | * |
| 86 | - * @since 0.18.x | |
| 87 | - * | |
| 88 | 85 | * @return void |
| 89 | 86 | */ |
| 90 | -function desktop_mode_compat_divi_fix_gutenberg_deps() { | |
| 87 | +function openstation_compat_divi_fix_gutenberg_deps() { | |
| 91 | 88 | global $wp_scripts; |
| 92 | 89 | |
| 93 | 90 | if ( ! ( $wp_scripts instanceof WP_Scripts ) ) { |
| 94 | 91 | return; |
| @@ -106,9 +103,9 @@ | ||
| 106 | 103 | $registration->deps[] = $dep; |
| 107 | 104 | } |
| 108 | 105 | } |
| 109 | 106 | |
| 110 | - if ( desktop_mode_is_chromeless_request() ) { | |
| 107 | + if ( openstation_is_chromeless_request() ) { | |
| 111 | 108 | wp_add_inline_script( |
| 112 | 109 | 'et-builder-gutenberg', |
| 113 | 110 | 'window.et_gb = window;', |
| 114 | 111 | 'before' |
| @@ -114,9 +111,9 @@ | ||
| 114 | 111 | 'before' |
| 115 | 112 | ); |
| 116 | 113 | } |
| 117 | 114 | } |
| 118 | -add_action( 'enqueue_block_editor_assets', 'desktop_mode_compat_divi_fix_gutenberg_deps', 999 ); | |
| 115 | +add_action( 'enqueue_block_editor_assets', 'openstation_compat_divi_fix_gutenberg_deps', 999 ); | |
| 119 | 116 | |
| 120 | 117 | /** |
| 121 | 118 | * Signal Divi's Visual Builder frame-helpers that the iframe context |
| 122 | 119 | * is "top-level-equivalent" so its `top_window` export resolves to |
| @@ -151,9 +148,9 @@ | ||
| 151 | 148 | * — exactly the classic-admin behavior. The flag costs nothing |
| 152 | 149 | * outside Divi (no other code in the WP stack reads `__Cypress__`) |
| 153 | 150 | * and is idempotent (we OR with the existing value). |
| 154 | 151 | * |
| 155 | - * Scope: only when the current user has desktop mode enabled AND | |
| 152 | + * Scope: only when the current user has OpenStation enabled AND | |
| 156 | 153 | * the rendered document is loaded inside an iframe (`window.top !== |
| 157 | 154 | * window`). The inline script is a few-byte no-op everywhere else. |
| 158 | 155 | * Front-end only — admin pages use `et_gb` (see above) and route |
| 159 | 156 | * through a different compat path. |
| @@ -160,24 +157,22 @@ | ||
| 160 | 157 | * |
| 161 | 158 | * Reported to Elegant Themes. Remove this hook when Divi makes |
| 162 | 159 | * `top_window` iframe-aware upstream. |
| 163 | 160 | * |
| 164 | - * @since 0.18.x | |
| 165 | - * | |
| 166 | 161 | * @return void |
| 167 | 162 | */ |
| 168 | -function desktop_mode_compat_divi_vb_iframe_signal() { | |
| 163 | +function openstation_compat_divi_vb_iframe_signal() { | |
| 169 | 164 | if ( is_admin() ) { |
| 170 | 165 | return; |
| 171 | 166 | } |
| 172 | - if ( ! desktop_mode_is_enabled() ) { | |
| 167 | + if ( ! openstation_is_enabled() ) { | |
| 173 | 168 | return; |
| 174 | 169 | } |
| 175 | 170 | // Bail when Divi isn't active — the inline script below is |
| 176 | 171 | // shaped entirely around Divi's frame-helpers and VB preloader. |
| 177 | 172 | // Other handlers in this file already gate on |
| 178 | - // `desktop_mode_compat_divi_is_active()`; this one was missed. | |
| 179 | - if ( ! desktop_mode_compat_divi_is_active() ) { | |
| 173 | + // `openstation_compat_divi_is_active()`; this one was missed. | |
| 174 | + if ( ! openstation_compat_divi_is_active() ) { | |
| 180 | 175 | return; |
| 181 | 176 | } |
| 182 | 177 | // `app_window=1` flags the inner VB iframe Divi spawns inside the |
| 183 | 178 | // `/?p=N&et_fb=1` page. The outer ("VB-top") frame is what hosts |
| @@ -186,9 +181,9 @@ | ||
| 186 | 181 | // VB-top — the inner frame's `__Cypress__` signal is enough. |
| 187 | 182 | // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only flag set by Divi itself when constructing the inner iframe. |
| 188 | 183 | $is_app_frame = isset( $_GET['app_window'] ) && '1' === sanitize_text_field( wp_unslash( $_GET['app_window'] ) ); |
| 189 | 184 | ?> |
| 190 | -<script id="desktop-mode-compat-divi-vb"> | |
| 185 | +<script id="os-compat-divi-vb"> | |
| 191 | 186 | ( function () { |
| 192 | 187 | if ( window.top === window ) { return; } |
| 193 | 188 | <?php if ( $is_app_frame ) : ?> |
| 194 | 189 | // Inside Divi's own inner builder iframe. We only want to |
| @@ -215,9 +210,9 @@ | ||
| 215 | 210 | * `window.top.document`. The intent is "and also clear it on the |
| 216 | 211 | * outer VB-top frame I'm rendered into." In classic admin |
| 217 | 212 | * `window.top` IS the VB-top, so that works. |
| 218 | 213 | * |
| 219 | - * In a Desktop Mode chromeless iframe, the nesting is one deeper | |
| 214 | + * In a OpenStation chromeless iframe, the nesting is one deeper | |
| 220 | 215 | * — the inner React app's `window.top` is the desktop shell, |
| 221 | 216 | * which has no Divi elements. Root.js cleans its own doc and |
| 222 | 217 | * no-ops on the shell, leaving THIS document's preloader stuck |
| 223 | 218 | * forever. |
| @@ -277,9 +272,9 @@ | ||
| 277 | 272 | } )(); |
| 278 | 273 | </script> |
| 279 | 274 | <?php |
| 280 | 275 | } |
| 281 | -add_action( 'wp_head', 'desktop_mode_compat_divi_vb_iframe_signal', 1 ); | |
| 276 | +add_action( 'wp_head', 'openstation_compat_divi_vb_iframe_signal', 1 ); | |
| 282 | 277 | |
| 283 | 278 | /** |
| 284 | 279 | * Iframe-side: hijack clicks on Divi's "Use Divi Builder" / |
| 285 | 280 | * "Edit With The Divi Builder" buttons and links, and hand the |
| @@ -288,9 +283,9 @@ | ||
| 288 | 283 | * |
| 289 | 284 | * Why we hijack instead of letting Divi navigate: |
| 290 | 285 | * |
| 291 | 286 | * Divi's Visual Builder fundamentally doesn't behave well inside |
| 292 | - * Desktop Mode's nested iframe chain (shell -> chromeless iframe | |
| 287 | + * OpenStation's nested iframe chain (shell -> chromeless iframe | |
| 293 | 288 | * -> Divi's inner app-frame). Earlier attempts to transparently |
| 294 | 289 | * eject mid-navigation hit a chain of subtle race conditions — |
| 295 | 290 | * Divi captures `Location.prototype` references early, makes its |
| 296 | 291 | * REST save through a path our `fetch`/`XHR` wraps don't reach, |
| @@ -295,9 +290,9 @@ | ||
| 295 | 290 | * Divi captures `Location.prototype` references early, makes its |
| 296 | 291 | * REST save through a path our `fetch`/`XHR` wraps don't reach, |
| 297 | 292 | * and the page-leave tears down our console before any diagnostic |
| 298 | 293 | * we add survives the navigation. The honest fix is to ask the |
| 299 | - * user, explicitly, whether they want to leave Desktop Mode for | |
| 294 | + * user, explicitly, whether they want to leave OpenStation for | |
| 300 | 295 | * this edit session. |
| 301 | 296 | * |
| 302 | 297 | * Detection is by visible text content on the clicked element |
| 303 | 298 | * rather than by selector — Divi changes the button class across |
| @@ -311,21 +306,19 @@ | ||
| 311 | 306 | * The handler also walks every same-origin nested iframe so the |
| 312 | 307 | * Gutenberg editor canvas (when Gutenberg keeps it for non-Divi |
| 313 | 308 | * blocks) is covered. |
| 314 | 309 | * |
| 315 | - * @since 0.18.x | |
| 316 | - * | |
| 317 | 310 | * @return void |
| 318 | 311 | */ |
| 319 | -function desktop_mode_compat_divi_eject_iframe_patch() { | |
| 320 | - if ( ! desktop_mode_is_chromeless_request() ) { | |
| 312 | +function openstation_compat_divi_eject_iframe_patch() { | |
| 313 | + if ( ! openstation_is_chromeless_request() ) { | |
| 321 | 314 | return; |
| 322 | 315 | } |
| 323 | - if ( ! desktop_mode_compat_divi_is_active() ) { | |
| 316 | + if ( ! openstation_compat_divi_is_active() ) { | |
| 324 | 317 | return; |
| 325 | 318 | } |
| 326 | 319 | ?> |
| 327 | -<script id="desktop-mode-compat-divi-vb-handoff"> | |
| 320 | +<script id="os-compat-divi-vb-handoff"> | |
| 328 | 321 | ( function () { |
| 329 | 322 | var BTN_TEXTS = [ |
| 330 | 323 | 'use divi builder', |
| 331 | 324 | 'use the divi builder', |
| @@ -342,9 +335,9 @@ | ||
| 342 | 335 | } |
| 343 | 336 | function postHandoff( currentUrl ) { |
| 344 | 337 | try { |
| 345 | 338 | window.top.postMessage( |
| 346 | - { type: 'desktop-mode-divi-vb-handoff', url: String( currentUrl ) }, | |
| 339 | + { type: 'os-divi-vb-handoff', url: String( currentUrl ) }, | |
| 347 | 340 | window.location.origin |
| 348 | 341 | ); |
| 349 | 342 | } catch ( e ) {} |
| 350 | 343 | } |
| @@ -366,10 +359,10 @@ | ||
| 366 | 359 | postHandoff( window.location.href ); |
| 367 | 360 | } |
| 368 | 361 | function attachClickListener( doc ) { |
| 369 | 362 | try { |
| 370 | - if ( doc.__desktopModeDiviHandoffAttached ) { return; } | |
| 371 | - doc.__desktopModeDiviHandoffAttached = true; | |
| 363 | + if ( doc.__openStationDiviHandoffAttached ) { return; } | |
| 364 | + doc.__openStationDiviHandoffAttached = true; | |
| 372 | 365 | doc.addEventListener( 'click', onClick, true ); |
| 373 | 366 | } catch ( e ) {} |
| 374 | 367 | } |
| 375 | 368 | function walkAndAttach( root ) { |
| @@ -380,10 +373,10 @@ | ||
| 380 | 373 | frames.forEach( function ( iframe ) { |
| 381 | 374 | try { |
| 382 | 375 | if ( iframe.contentDocument ) { walkAndAttach( iframe.contentDocument ); } |
| 383 | 376 | } catch ( e ) {} |
| 384 | - if ( iframe.__desktopModeDiviHandoffHooked ) { return; } | |
| 385 | - iframe.__desktopModeDiviHandoffHooked = true; | |
| 377 | + if ( iframe.__openStationDiviHandoffHooked ) { return; } | |
| 378 | + iframe.__openStationDiviHandoffHooked = true; | |
| 386 | 379 | iframe.addEventListener( 'load', function () { |
| 387 | 380 | try { if ( iframe.contentDocument ) { walkAndAttach( iframe.contentDocument ); } } catch ( e ) {} |
| 388 | 381 | } ); |
| 389 | 382 | } ); |
| @@ -401,13 +394,13 @@ | ||
| 401 | 394 | } )(); |
| 402 | 395 | </script> |
| 403 | 396 | <?php |
| 404 | 397 | } |
| 405 | -add_action( 'admin_head', 'desktop_mode_compat_divi_eject_iframe_patch', 0 ); | |
| 398 | +add_action( 'admin_head', 'openstation_compat_divi_eject_iframe_patch', 0 ); | |
| 406 | 399 | |
| 407 | 400 | /** |
| 408 | 401 | * Parent-shell side: receive the handoff message, ask the user |
| 409 | - * to confirm via `wp.desktop.confirm()`, and on accept navigate | |
| 402 | + * to confirm via `wp.os.confirm()`, and on accept navigate | |
| 410 | 403 | * `window.top.location.href` to the iframe's current URL — which |
| 411 | 404 | * is the post-edit page. The user lands at top level on the same |
| 412 | 405 | * post they were editing, clicks "Use Divi Builder" again with a |
| 413 | 406 | * single browser tab, and Divi runs in its native single-frame |
| @@ -419,38 +412,33 @@ | ||
| 419 | 412 | * Same-origin guards: the message event must originate from our |
| 420 | 413 | * own origin AND the URL we navigate to must parse back to the |
| 421 | 414 | * same origin. Foreign frames can't trigger the handoff. |
| 422 | 415 | * |
| 423 | - * @since 0.18.x | |
| 424 | - * | |
| 425 | 416 | * @return void |
| 426 | 417 | */ |
| 427 | -function desktop_mode_compat_divi_eject_parent_listener() { | |
| 428 | - if ( ! desktop_mode_is_enabled() ) { | |
| 418 | +function openstation_compat_divi_eject_parent_listener() { | |
| 419 | + if ( ! openstation_is_shell_request() ) { | |
| 429 | 420 | return; |
| 430 | 421 | } |
| 431 | - if ( desktop_mode_is_chromeless_request() || desktop_mode_is_classic_request() ) { | |
| 422 | + if ( ! openstation_compat_divi_is_active() ) { | |
| 432 | 423 | return; |
| 433 | 424 | } |
| 434 | - if ( ! desktop_mode_compat_divi_is_active() ) { | |
| 435 | - return; | |
| 436 | - } | |
| 437 | 425 | ?> |
| 438 | -<script id="desktop-mode-compat-divi-vb-handoff-parent"> | |
| 426 | +<script id="os-compat-divi-vb-handoff-parent"> | |
| 439 | 427 | ( function () { |
| 440 | 428 | // Reshape the iframe's URL into a top-level classic-admin URL. |
| 441 | - // The iframe carries `desktop_mode_chromeless=1`, which would | |
| 429 | + // The iframe carries `openstation_chromeless=1`, which would | |
| 442 | 430 | // keep the chromeless render alive even at top level — leaving |
| 443 | 431 | // the user on what looks like the same headless Gutenberg they |
| 444 | 432 | // already had inside the window. We want a normal wp-admin page |
| 445 | 433 | // instead, so strip that flag and add `desktop_mode_classic=1` |
| 446 | - // so our own `desktop_mode_redirect_plain_admin_to_portal()` in | |
| 434 | + // so our own `openstation_redirect_plain_admin_to_portal()` in | |
| 447 | 435 | // `includes/portal.php` skips its portal-bounce for this load. |
| 448 | 436 | function handoffUrl( raw ) { |
| 449 | 437 | try { |
| 450 | 438 | var parsed = new URL( String( raw || '' ), window.location.href ); |
| 451 | 439 | if ( parsed.origin !== window.location.origin ) { return null; } |
| 452 | - parsed.searchParams.delete( 'desktop_mode_chromeless' ); | |
| 440 | + parsed.searchParams.delete( 'openstation_chromeless' ); | |
| 453 | 441 | parsed.searchParams.set( 'desktop_mode_classic', '1' ); |
| 454 | 442 | return parsed.toString(); |
| 455 | 443 | } catch ( e ) { return null; } |
| 456 | 444 | } |
| @@ -455,22 +443,22 @@ | ||
| 455 | 443 | } catch ( e ) { return null; } |
| 456 | 444 | } |
| 457 | 445 | window.addEventListener( 'message', function ( ev ) { |
| 458 | 446 | if ( ev.origin !== window.location.origin ) { return; } |
| 459 | - if ( ! ev.data || ev.data.type !== 'desktop-mode-divi-vb-handoff' ) { return; } | |
| 447 | + if ( ! ev.data || ev.data.type !== 'os-divi-vb-handoff' ) { return; } | |
| 460 | 448 | var url = handoffUrl( ev.data.url ); |
| 461 | 449 | if ( ! url ) { return; } |
| 462 | 450 | var promptUser; |
| 463 | - if ( window.wp && window.wp.desktop && typeof window.wp.desktop.confirm === 'function' ) { | |
| 464 | - promptUser = window.wp.desktop.confirm( { | |
| 451 | + if ( window.wp && window.wp.os && typeof window.wp.os.confirm === 'function' ) { | |
| 452 | + promptUser = window.wp.os.confirm( { | |
| 465 | 453 | title: 'Divi needs its own browser tab', |
| 466 | - message: 'Divi\u2019s Visual Builder cannot run inside a Desktop Mode window \u2014 it needs the full browser tab to render and save correctly. There is no workaround on our side; Divi simply doesn\u2019t support being nested.', | |
| 454 | + message: 'Divi\u2019s Visual Builder cannot run inside a OpenStation window \u2014 it needs the full browser tab to render and save correctly. There is no workaround on our side; Divi simply doesn\u2019t support being nested.', | |
| 467 | 455 | confirmLabel: 'Open Divi in this tab', |
| 468 | 456 | hideCancel: true, |
| 469 | 457 | dismissable: true, |
| 470 | 458 | } ); |
| 471 | 459 | } else { |
| 472 | - // Defense-in-depth no-op. `wp.desktop.confirm` is | |
| 460 | + // Defense-in-depth no-op. `wp.os.confirm` is | |
| 473 | 461 | // reliably present on every shell page where this |
| 474 | 462 | // listener emits, so this branch is unreachable in |
| 475 | 463 | // practice. A `window.confirm` here would violate the |
| 476 | 464 | // codebase-wide "no native dialogs" rule (see CLAUDE.md); |
| @@ -484,9 +472,9 @@ | ||
| 484 | 472 | } )(); |
| 485 | 473 | </script> |
| 486 | 474 | <?php |
| 487 | 475 | } |
| 488 | -add_action( 'admin_footer', 'desktop_mode_compat_divi_eject_parent_listener', 1 ); | |
| 476 | +add_action( 'admin_footer', 'openstation_compat_divi_eject_parent_listener', 1 ); | |
| 489 | 477 | |
| 490 | 478 | |
| 491 | 479 | /** |
| 492 | 480 | * Detect whether Divi (theme or standalone Divi Builder plugin) |
| @@ -492,14 +480,12 @@ | ||
| 492 | 480 | * Detect whether Divi (theme or standalone Divi Builder plugin) |
| 493 | 481 | * is active. Used to gate both the iframe-side patcher and the |
| 494 | 482 | * parent-side listener — both no-ops on non-Divi sites. |
| 495 | 483 | * |
| 496 | - * @since 0.18.x | |
| 497 | - * | |
| 498 | 484 | * @return bool True when the Divi theme is active OR the Divi |
| 499 | 485 | * Builder plugin is active. |
| 500 | 486 | */ |
| 501 | -function desktop_mode_compat_divi_is_active() { | |
| 487 | +function openstation_compat_divi_is_active() { | |
| 502 | 488 | $theme = wp_get_theme(); |
| 503 | 489 | if ( $theme instanceof WP_Theme ) { |
| 504 | 490 | $name = (string) $theme->get( 'Name' ); |
| 505 | 491 | $template = (string) $theme->get_template(); |