PluginProbe
OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin / 1.1.13
OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin v1.1.13
1.1.13 1.1.12 1.1.11 1.1.10 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 All 37 releases
← All changes | includes/assets.php +306 -258 0.9.7 → 1.1.13 View file →
@@ -1,12 +1,12 @@
1 1 <?php
2 2 /**
3 - * Desktop Mode asset registration.
3 + * OpenStation asset registration.
4 4 *
5 - * Registers all desktop-mode CSS and JS handles with WordPress so they can
5 + * Registers all openstation CSS and JS handles with WordPress so they can
6 6 * be enqueued from anywhere in the plugin (or by third parties).
7 7 *
8 - * @package WPDesktopMode
8 + * @package OpenStation
9 9 */
10 10
11 11 defined( 'ABSPATH' ) || exit;
12 12
@@ -16,16 +16,14 @@
16 16 * Sub-sheet URLs carry no `?ver=` of their own, so the parent's stamp is
17 17 * the only cache key the browser ever sees for the subtree — it must
18 18 * move when any member changes.
19 19 *
20 - * @since 0.9.4
21 - *
22 20 * @param string $relative Stylesheet path relative to the plugin dir.
23 21 * @param string $fallback Version to use when the file is missing.
24 22 * @return string Version string.
25 23 */
26 -function desktop_mode_css_subtree_version( $relative, $fallback ) {
27 - $root = DESKTOP_MODE_DIR . $relative;
24 +function openstation_css_subtree_version( $relative, $fallback ) {
25 + $root = OPENSTATION_DIR . $relative;
28 26 if ( ! file_exists( $root ) ) {
29 27 return (string) $fallback;
30 28 }
31 29 $max = (int) filemtime( $root );
@@ -50,18 +48,16 @@
50 48 return (string) $max;
51 49 }
52 50
53 51 /**
54 - * Registers the desktop mode CSS and JS handles.
55 - *
56 - * @since 0.1.0
52 + * Registers the OpenStation CSS and JS handles.
57 53 */
58 -function desktop_mode_register_assets() {
59 - $version = DESKTOP_MODE_VERSION;
60 - $suffix = desktop_mode_asset_suffix();
54 +function openstation_register_assets() {
55 + $version = OPENSTATION_VERSION;
56 + $suffix = openstation_asset_suffix();
61 57
62 58 // `filemtime`-stamped version for built bundles. The plugin-wide
63 - // `DESKTOP_MODE_VERSION` is bumped per release, but the bundles
59 + // `OPENSTATION_VERSION` is bumped per release, but the bundles
64 60 // iterate faster — without a per-file mtime stamp, two clients
65 61 // loading the same `?ver=…` URL can be served different bytes
66 62 // (whichever build was on disk at upload time). Stamping with the
67 63 // file's modification time guarantees the URL changes whenever the
@@ -68,87 +64,185 @@
68 64 // file does, so "is my fix deployed?" is answerable from the
69 65 // network tab. Falls back to `$version` when the file is missing
70 66 // (test envs that import this file before the build runs).
71 67 $built_version = static function ( $relative ) use ( $version ) {
72 - $path = DESKTOP_MODE_DIR . $relative;
68 + $path = OPENSTATION_DIR . $relative;
73 69 return file_exists( $path ) ? (string) filemtime( $path ) : $version;
74 70 };
75 71
76 -
77 72 // Styles.
73 + // `filemtime`-stamped, NOT the plugin-wide `$version`. This file
74 + // is the token catalogue every other sheet resolves `var()`s
75 + // against, and it changes whenever the palette does — which is a
76 + // lot more often than the plugin version is bumped. With a static
77 + // stamp the browser holds the old palette until a hard reload,
78 + // and the symptom is maddening: a themed shell where some
79 + // surfaces update and others don't.
78 80 wp_register_style(
79 - 'desktop-mode-variables',
80 - DESKTOP_MODE_URL . 'assets/css/variables.css',
81 + 'os-variables',
82 + OPENSTATION_URL . 'assets/css/variables.css',
81 83 array(),
82 - $version
84 + $built_version( 'assets/css/variables.css' )
83 85 );
84 86 // `filemtime`-stamped so the `<link rel="stylesheet">` URL matches the
85 87 // `<link rel="preload" as="style">` hint emitted by
86 - // `desktop_mode_print_preload_hints()` (which stamps with filemtime).
88 + // `openstation_print_preload_hints()` (which stamps with filemtime).
87 89 // Registering this with the plain `$version` instead produced two
88 90 // different `?ver=` query strings for the same file, so the browser
89 91 // never matched the preload to the stylesheet and logged "preloaded
90 92 // but not used within a few seconds from the window's load event".
91 93 wp_register_style(
92 - 'desktop-mode',
93 - DESKTOP_MODE_URL . 'assets/css/desktop.css',
94 - array( 'desktop-mode-variables' ),
94 + 'openstation',
95 + OPENSTATION_URL . 'assets/css/desktop.css',
96 + array( 'os-variables' ),
95 97 $built_version( 'assets/css/desktop.css' )
96 98 );
97 - // `filemtime`-stamped — window-chrome iteration (drop overlays,
98 - // new drag affordances, third-party-plugin compat) lands faster
99 - // than plugin version bumps. Without an mtime stamp the browser
100 - // keeps `?ver=<plugin-version>` valid for the whole release cycle
101 - // and the user keeps seeing yesterday's CSS even after a hard
102 - // reload.
103 - //
104 - // The stamp covers the whole `@import` SUBTREE, not just the parent
105 - // file: `windows.css` imports `window-chrome.css`,
106 - // `os-settings.css`, … and those sub-sheet URLs carry no `?ver=` of
107 - // their own. Stamping only the parent meant an edit to a sub-sheet
108 - // never changed any URL the browser knew about, so users kept
109 - // yesterday's rules until an unrelated parent edit came along
110 - // (exactly how the wallpaper-description card shipped with stale
111 - // layout). The subtree max-mtime busts the parent whenever ANY
112 - // sub-sheet changes; the re-parsed parent then re-requests the
113 - // sub-sheets, whose fresh mtimes fail heuristic-cache reuse.
99 +
100 + /*
101 + * Window styles — one handle per sheet, chained by dependency.
102 + *
103 + * These used to be `@import url( … )`ed from `windows.css` under
104 + * the single `os-windows` handle. That was a standing
105 + * cache bug: an `@import` URL carries no `?ver=`, so a changed
106 + * sub-sheet had no URL for the browser to invalidate. Stamping the
107 + * PARENT with the subtree's max mtime (which is what
108 + * `openstation_css_subtree_version()` was for) made the browser
109 + * re-fetch `windows.css` and then request each sub-sheet at an
110 + * unchanged URL — free to be served from its heuristic cache. The
111 + * result was edits not landing until a hard refresh, and rules
112 + * being relocated into `windows.css` purely to dodge it.
113 + *
114 + * Now every sheet is separately registered with its own
115 + * `filemtime` stamp, so each has a real cache key.
116 + *
117 + * THE DEPENDENCY CHAIN IS LOAD-BEARING. WordPress prints
118 + * dependencies before dependents, so chaining each sheet to the
119 + * previous one reproduces the order the `@import` block had, and
120 + * `os-windows` (which depends on the last link) still
121 + * prints after them and still wins ties:
122 + *
123 + * window-chrome → window-states → effects → window-links
124 + * → windows
125 + *
126 + * `window-overview` is deliberately NOT in this chain — it is
127 + * registered below, after `os-windows`, so it can load deferred.
128 + * Adding a sheet here means splicing it into the chain, not
129 + * appending an unrelated dependency: order is the contract.
130 + * (The Preferences window's sheet is not here at all: it rides
131 + * the `apps/os-settings/` app as a first-open companion style.)
132 + */
133 + $window_sheets = array(
134 + 'os-window-chrome' => 'assets/css/window-chrome.css',
135 + 'os-window-states' => 'assets/css/window-states.css',
136 + 'os-effects' => 'assets/css/effects.css',
137 + 'os-window-links' => 'assets/css/window-links.css',
138 + );
139 + $previous = array( 'os-variables', 'dashicons' );
140 + foreach ( $window_sheets as $handle => $relative ) {
141 + wp_register_style(
142 + $handle,
143 + OPENSTATION_URL . $relative,
144 + $previous,
145 + $built_version( $relative )
146 + );
147 + $previous = array( $handle );
148 + }
149 +
150 + // Entry point. Depends on the tail of the chain above, so
151 + // enqueuing this one handle still pulls in every critical window
152 + // sheet — the behaviour callers had when they were `@import`s.
114 153 wp_register_style(
115 - 'desktop-mode-windows',
116 - DESKTOP_MODE_URL . 'assets/css/windows.css',
117 - array( 'desktop-mode-variables', 'dashicons' ),
118 - desktop_mode_css_subtree_version( 'assets/css/windows.css', $version )
154 + 'os-windows',
155 + OPENSTATION_URL . 'assets/css/windows.css',
156 + $previous,
157 + $built_version( 'assets/css/windows.css' )
119 158 );
120 - // Split out of the `windows.css` @import chain so they can load
121 - // deferred (see `desktop_mode_defer_non_critical_styles()`): the
122 - // UI they style — the OS Settings panel and the window overview —
123 - // is lazy-loaded JS that can never be on screen at first paint,
124 - // so ~47 KB of CSS has no business blocking render. They depend
125 - // on `desktop-mode-windows` to keep the historical cascade order
126 - // (they used to be imported after the chrome/states sub-sheets).
159 + // Loads DEFERRED (see `openstation_defer_non_critical_styles()`):
160 + // the UI it styles — the window overview — is lazy-loaded JS that
161 + // can never be on screen at first paint, so its CSS has no
162 + // business blocking render. It depends on `os-windows` so it
163 + // prints after it, preserving the cascade position it had as an
164 + // `@import`.
127 165 wp_register_style(
128 - 'desktop-mode-window-overview',
129 - DESKTOP_MODE_URL . 'assets/css/window-overview.css',
130 - array( 'desktop-mode-windows' ),
166 + 'os-window-overview',
167 + OPENSTATION_URL . 'assets/css/window-overview.css',
168 + array( 'os-windows' ),
131 169 $built_version( 'assets/css/window-overview.css' )
132 170 );
171 + // Solo mode — one window, no desk around it. Loads last so it can
172 + // hide surfaces the sheets above declared, and only enqueues on a
173 + // solo request, so a normal shell never pays for it.
133 174 wp_register_style(
134 - 'desktop-mode-os-settings',
135 - DESKTOP_MODE_URL . 'assets/css/os-settings.css',
136 - array( 'desktop-mode-windows' ),
137 - $built_version( 'assets/css/os-settings.css' )
175 + 'os-solo',
176 + OPENSTATION_URL . 'assets/css/solo.css',
177 + array( 'os-windows' ),
178 + $built_version( 'assets/css/solo.css' )
138 179 );
139 180 wp_register_style(
140 - 'desktop-mode-dock',
141 - DESKTOP_MODE_URL . 'assets/css/dock.css',
142 - array( 'desktop-mode-variables', 'dashicons' ),
181 + 'os-dock',
182 + OPENSTATION_URL . 'assets/css/dock.css',
183 + array( 'os-variables', 'dashicons' ),
143 184 $built_version( 'assets/css/dock.css' )
144 185 );
186 + // The Taskbar rail renderer. Scoped to the rail it stamps, so it is
187 + // inert under the icon strip; loaded with the dock because the
188 + // renderer can be picked live.
145 189 wp_register_style(
146 - 'desktop-mode-dock-peek',
147 - DESKTOP_MODE_URL . 'assets/css/dock-peek.css',
148 - array( 'desktop-mode-dock' ),
149 - $version
190 + 'os-dock-taskbar',
191 + OPENSTATION_URL . 'assets/css/dock-taskbar.css',
192 + array( 'os-dock' ),
193 + $built_version( 'assets/css/dock-taskbar.css' )
150 194 );
195 + wp_register_style(
196 + 'os-dock-peek',
197 + OPENSTATION_URL . 'assets/css/dock-peek.css',
198 + array( 'os-dock' ),
199 + $built_version( 'assets/css/dock-peek.css' )
200 + );
201 + // The phone layer. Every rule is scoped to
202 + // `html[data-os-mode="mobile"]`, so the sheet is inert on a
203 + // desktop and the first paint on a phone is already right (the
204 + // head stamp writes the attribute before any stylesheet applies).
205 + // Depends on the dock and window sheets because it overrides them.
206 + wp_register_style(
207 + 'os-mobile',
208 + OPENSTATION_URL . 'assets/css/mobile.css',
209 + array( 'os-variables', 'dashicons', 'os-dock', 'os-windows' ),
210 + $built_version( 'assets/css/mobile.css' )
211 + );
212 + // The workspace wizard. Scoped to `.os-workspace-wizard`, so it is
213 + // inert until the user opens it from the overview bar's `+` or a
214 + // tile's Edit. Those controls are styled with the rest of the bar
215 + // in `window-overview.css`.
216 + wp_register_style(
217 + 'os-workspaces',
218 + OPENSTATION_URL . 'assets/css/workspaces.css',
219 + array( 'os-variables', 'dashicons' ),
220 + $built_version( 'assets/css/workspaces.css' )
221 + );
222 + // Keyboard-shortcuts window. Scoped to `.os-shortcuts`, so it is
223 + // inert until the System menu opens the window, and unconditional
224 + // for the same reason the layout sheet is: the window can be
225 + // opened at any moment and a deferred sheet would paint it raw.
226 + wp_register_style(
227 + 'os-shortcuts',
228 + OPENSTATION_URL . 'assets/css/shortcuts.css',
229 + array( 'os-variables' ),
230 + $built_version( 'assets/css/shortcuts.css' )
231 + );
232 + // The OpenStation desktop layout — the core/plugin seam on the rail
233 + // plus the constellation hover-submenu flyout. Both surfaces are
234 + // scoped (`[data-os-layout="openstation"]` / `.os-constellation`),
235 + // so the sheet is inert in every other layout and is loaded
236 + // unconditionally rather than gated on the user's current pick:
237 + // the layout is switchable live from OpenStation Preferences, and a
238 + // conditional enqueue would leave the first switch unstyled.
239 + wp_register_style(
240 + 'os-openstation-layout',
241 + OPENSTATION_URL . 'assets/css/openstation-layout.css',
242 + array( 'os-dock' ),
243 + $built_version( 'assets/css/openstation-layout.css' )
244 + );
151 245 // `filemtime`-stamped — the chromeless overrides iterate faster
152 246 // than the plugin-wide version bumps (per-page compat shims and
153 247 // page-title-action exceptions land in patches), and a stale
154 248 // cached copy means the user sees yesterday's rules. Without the
@@ -154,11 +248,11 @@
154 248 // cached copy means the user sees yesterday's rules. Without the
155 249 // stamp, the browser keeps `?ver=0.8.1` valid for the whole
156 250 // release cycle.
157 251 wp_register_style(
158 - 'desktop-mode-chromeless',
159 - DESKTOP_MODE_URL . 'assets/css/chromeless.css',
160 - array( 'desktop-mode' ),
252 + 'os-chromeless',
253 + OPENSTATION_URL . 'assets/css/chromeless.css',
254 + array( 'openstation' ),
161 255 $built_version( 'assets/css/chromeless.css' )
162 256 );
163 257
164 258 // `filemtime`-stamped — the AI assistant surface (error states,
@@ -167,70 +261,40 @@
167 261 // valid for the whole release cycle and the user keeps seeing
168 262 // yesterday's CSS even after a hard reload.
169 263 wp_register_style(
170 264 'desktop-mode-ai-assistant',
171 - DESKTOP_MODE_URL . 'assets/css/ai-assistant.css',
172 - array( 'desktop-mode-variables' ),
265 + OPENSTATION_URL . 'assets/css/ai-assistant.css',
266 + array( 'os-variables' ),
173 267 $built_version( 'assets/css/ai-assistant.css' )
174 268 );
175 269
176 270 wp_register_style(
177 271 'desktop-mode-bug-report',
178 - DESKTOP_MODE_URL . 'assets/css/bug-report.css',
179 - array( 'desktop-mode-variables' ),
180 - $version
272 + OPENSTATION_URL . 'assets/css/bug-report.css',
273 + array( 'os-variables' ),
274 + $built_version( 'assets/css/bug-report.css' )
181 275 );
182 276
183 277 // `filemtime` instead of the plugin-wide `$version` for the
184 278 // recycle-bin CSS — this file iterates faster than the bundle
185 279 // and we never want a stale CSS cache to mask a real fix.
186 - $recycle_bin_css = DESKTOP_MODE_DIR . 'assets/css/recycle-bin.css';
280 + $recycle_bin_css = OPENSTATION_DIR . 'assets/css/recycle-bin.css';
187 281 wp_register_style(
188 282 'desktop-mode-recycle-bin',
189 - DESKTOP_MODE_URL . 'assets/css/recycle-bin.css',
190 - array( 'desktop-mode-variables', 'dashicons' ),
283 + OPENSTATION_URL . 'assets/css/recycle-bin.css',
284 + array( 'os-variables', 'dashicons' ),
191 285 file_exists( $recycle_bin_css ) ? (string) filemtime( $recycle_bin_css ) : $version
192 286 );
193 287
194 - // `filemtime` for the native Posts window CSS — same rationale as
195 - // the recycle-bin CSS: bundle iterates faster than the plugin
196 - // version and stale caches are worse than the cost of a 304.
197 - $posts_window_css = DESKTOP_MODE_DIR . 'assets/css/posts-window.css';
198 - wp_register_style(
199 - 'desktop-mode-posts-window',
200 - DESKTOP_MODE_URL . 'assets/css/posts-window.css',
201 - array( 'desktop-mode-variables', 'dashicons' ),
202 - file_exists( $posts_window_css ) ? (string) filemtime( $posts_window_css ) : $version
203 - );
204 -
205 - // Native Plugins window CSS — same `filemtime`-cache-bust posture
206 - // as the Posts/Recycle Bin styles.
207 - $plugins_window_css = DESKTOP_MODE_DIR . 'assets/css/plugins-window.css';
208 - wp_register_style(
209 - 'desktop-mode-plugins-window',
210 - DESKTOP_MODE_URL . 'assets/css/plugins-window.css',
211 - array( 'desktop-mode-variables', 'dashicons' ),
212 - file_exists( $plugins_window_css ) ? (string) filemtime( $plugins_window_css ) : $version
213 - );
214 -
215 - // Native Comments window CSS — same `filemtime` posture.
216 - $comments_window_css = DESKTOP_MODE_DIR . 'assets/css/comments-window.css';
217 - wp_register_style(
218 - 'desktop-mode-comments-window',
219 - DESKTOP_MODE_URL . 'assets/css/comments-window.css',
220 - array( 'desktop-mode-variables', 'dashicons' ),
221 - file_exists( $comments_window_css ) ? (string) filemtime( $comments_window_css ) : $version
222 - );
223 -
224 288 // Files-on-the-Desktop tile + layer styles. `filemtime` for the
225 - // same reason as the recycle-bin / posts-window CSS: this file
289 + // same reason as the recycle-bin CSS: this file
226 290 // iterates faster than the plugin version, and a stale cache
227 291 // would mask a real fix.
228 - $desktop_files_css = DESKTOP_MODE_DIR . 'assets/css/desktop-files.css';
292 + $desktop_files_css = OPENSTATION_DIR . 'assets/css/desktop-files.css';
229 293 wp_register_style(
230 - 'desktop-mode-files',
231 - DESKTOP_MODE_URL . 'assets/css/desktop-files.css',
232 - array( 'desktop-mode-variables', 'dashicons' ),
294 + 'os-files',
295 + OPENSTATION_URL . 'assets/css/desktop-files.css',
296 + array( 'os-variables', 'dashicons' ),
233 297 file_exists( $desktop_files_css ) ? (string) filemtime( $desktop_files_css ) : $version
234 298 );
235 299
236 300 // Games hub window (launcher grid, scoreboard, challenges) +
@@ -235,41 +299,58 @@
235 299
236 300 // Games hub window (launcher grid, scoreboard, challenges) +
237 301 // per-game styles. Same `filemtime` cache-bust posture as the
238 302 // other fast-iterating feature stylesheets.
239 - $games_css = DESKTOP_MODE_DIR . 'assets/css/games.css';
303 + $games_css = OPENSTATION_DIR . 'assets/css/games.css';
240 304 wp_register_style(
241 305 'desktop-mode-games',
242 - DESKTOP_MODE_URL . 'assets/css/games.css',
243 - array( 'desktop-mode-variables', 'dashicons' ),
306 + OPENSTATION_URL . 'assets/css/games.css',
307 + array( 'os-variables', 'dashicons' ),
244 308 file_exists( $games_css ) ? (string) filemtime( $games_css ) : $version
245 309 );
246 - $game_inkfall_css = DESKTOP_MODE_DIR . 'assets/css/game-inkfall.css';
310 + $game_inkfall_css = OPENSTATION_DIR . 'assets/css/game-inkfall.css';
247 311 wp_register_style(
248 - 'desktop-mode-game-inkfall',
249 - DESKTOP_MODE_URL . 'assets/css/game-inkfall.css',
250 - array( 'desktop-mode-variables' ),
312 + 'os-game-inkfall',
313 + OPENSTATION_URL . 'assets/css/game-inkfall.css',
314 + array( 'os-variables' ),
251 315 file_exists( $game_inkfall_css ) ? (string) filemtime( $game_inkfall_css ) : $version
252 316 );
253 - $game_alphabet_soup_css = DESKTOP_MODE_DIR . 'assets/css/game-alphabet-soup.css';
317 + $game_alphabet_soup_css = OPENSTATION_DIR . 'assets/css/game-alphabet-soup.css';
254 318 wp_register_style(
255 - 'desktop-mode-game-alphabet-soup',
256 - DESKTOP_MODE_URL . 'assets/css/game-alphabet-soup.css',
257 - array( 'desktop-mode-variables' ),
319 + 'os-game-alphabet-soup',
320 + OPENSTATION_URL . 'assets/css/game-alphabet-soup.css',
321 + array( 'os-variables' ),
258 322 file_exists( $game_alphabet_soup_css ) ? (string) filemtime( $game_alphabet_soup_css ) : $version
259 323 );
260 324
261 325 // Pinned-notes layer styles (paper, pushpin, pastel tokens, pin
262 326 // animations). Same `filemtime` cache-bust posture as the other
263 - // fast-iterating feature stylesheets above.
264 - $notes_css = DESKTOP_MODE_DIR . 'assets/css/notes.css';
327 + // fast-iterating feature stylesheets above. Depends on `os-files`
328 + // because a pinned note dresses the canonical `.os-file-tile`
329 + // chrome — anything that restyles a tile has to print after the
330 + // file that declares one.
331 + $notes_css = OPENSTATION_DIR . 'assets/css/notes.css';
265 332 wp_register_style(
266 - 'desktop-mode-notes',
267 - DESKTOP_MODE_URL . 'assets/css/notes.css',
268 - array( 'desktop-mode-variables', 'dashicons' ),
333 + 'os-notes',
334 + OPENSTATION_URL . 'assets/css/notes.css',
335 + array( 'os-variables', 'dashicons', 'os-files' ),
269 336 file_exists( $notes_css ) ? (string) filemtime( $notes_css ) : $version
270 337 );
271 338
339 + // Announcement-dialog styles (scrim, hero card, buttons). Registered
340 + // always, enqueued only for a user who is actually owed the
341 + // announcement — see the gate in `openstation_enqueue_assets()`. It
342 + // is not lazy-loaded on top of that: on the one boot where it does
343 + // go out, the dialog opens from the main bundle a second later, and
344 + // a fetch racing that would show an unstyled card.
345 + $announce_css = OPENSTATION_DIR . 'assets/css/announce.css';
346 + wp_register_style(
347 + 'os-announce',
348 + OPENSTATION_URL . 'assets/css/announce.css',
349 + array( 'os-variables' ),
350 + file_exists( $announce_css ) ? (string) filemtime( $announce_css ) : $version
351 + );
352 +
272 353 // Scripts.
273 354 //
274 355 // `wp-hooks` — the shell exposes a WordPress-style filter/action
275 356 // API (`window.wp.hooks`) to third-party plugins.
@@ -278,10 +359,10 @@
278 359 // lookups. Both handles are core-shipped but only pre-enqueued
279 360 // when Gutenberg-adjacent deps pull them in, so we list them
280 361 // explicitly to guarantee load order.
281 362 wp_register_script(
282 - 'desktop-mode',
283 - DESKTOP_MODE_URL . 'assets/js/desktop' . $suffix . '.js',
363 + 'openstation',
364 + OPENSTATION_URL . 'assets/js/desktop' . $suffix . '.js',
284 365 // `heartbeat` + `jquery` — the recycle-bin badge module
285 366 // (loaded as part of this bundle) opts into the WordPress
286 367 // Heartbeat API so the count tile / desktop-icon badge
287 368 // stays in sync even when the bin window is closed.
@@ -289,9 +370,9 @@
289 370 $built_version( 'assets/js/desktop' . $suffix . '.js' ),
290 371 // Footer + defer: the shell boots on DOMContentLoaded anyway,
291 372 // so deferring frees the parser instead of blocking at the
292 373 // footer print point. Both inline payloads attached to this
293 - // handle (`__desktopModeMenuCommands`, the jazz-quote version
374 + // handle (`__openStationMenuCommands`, the jazz-quote version
294 375 // stamp) are `'before'`-position, which WP keeps as blocking
295 376 // inline ahead of a deferred tag — order is preserved. On WP
296 377 // < 6.3 the array collapses to a truthy `$in_footer`, same as
297 378 // before.
@@ -300,10 +381,10 @@
300 381 'strategy' => 'defer',
301 382 )
302 383 );
303 384
304 - // `desktop-mode-iframe-bridge` — opt-in iframe-side bridge that
305 - // provides `wp.desktop.iframe.publish/subscribe/onConnection/
385 + // `os-iframe-bridge` — opt-in iframe-side bridge that
386 + // provides `wp.os.iframe.publish/subscribe/onConnection/
306 387 // requestConnection` to any same-origin iframe that enqueues it.
307 388 // Same code is also injected inline by the chromeless bridge
308 389 // (so chromeless wp-admin pages don't need a separate enqueue)
309 390 // and auto-injected when a native window opts in via
@@ -309,19 +390,60 @@
309 390 // and auto-injected when a native window opts in via
310 391 // `iframeContent: { bridge: true }`. Plugins targeting their
311 392 // own iframe pages just enqueue this handle.
312 393 wp_register_script(
313 - 'desktop-mode-iframe-bridge',
314 - DESKTOP_MODE_URL . 'assets/js/iframe-bridge' . $suffix . '.js',
394 + 'os-iframe-bridge',
395 + OPENSTATION_URL . 'assets/js/iframe-bridge' . $suffix . '.js',
315 396 array(),
316 397 $built_version( 'assets/js/iframe-bridge' . $suffix . '.js' ),
317 398 true
318 399 );
319 400
320 - // `desktop-mode-gutenberg-drop-receiver` — iframe-side bundle
401 + // `os-deactivation-feedback` — the dialog that asks one optional
402 + // question when an admin deactivates OpenStation. Enqueued on
403 + // `plugins.php` (classic, chromeless and network admin) by
404 + // `includes/feedback/deactivation.php`, and lazy-loaded by the
405 + // native Plugins app from its config block. Plain DOM on purpose:
406 + // the classic screen has no `<os-*>` kit.
407 + wp_register_script(
408 + 'os-deactivation-feedback',
409 + OPENSTATION_URL . 'assets/js/deactivation-feedback' . $suffix . '.js',
410 + array( 'wp-i18n' ),
411 + $built_version( 'assets/js/deactivation-feedback' . $suffix . '.js' ),
412 + true
413 + );
414 + wp_set_script_translations(
415 + 'os-deactivation-feedback',
416 + 'desktop-mode',
417 + OPENSTATION_DIR . 'languages'
418 + );
419 + $feedback_css = OPENSTATION_DIR . 'assets/css/deactivation-feedback.css';
420 + wp_register_style(
421 + 'os-deactivation-feedback',
422 + OPENSTATION_URL . 'assets/css/deactivation-feedback.css',
423 + array(),
424 + file_exists( $feedback_css ) ? (string) filemtime( $feedback_css ) : $version
425 + );
426 +
427 + // `os-chromeless-bridge` — the iframe side of every window,
428 + // enqueued on `admin_footer` by
429 + // `openstation_chromeless_bridge_script()` with its per-request
430 + // data attached as a `before` inline block. Registered here (not
431 + // there) so the handle exists before the enqueue and so the asset
432 + // guard's OPENSTATION_URL snapshot protects it like every other
433 + // bundle of ours.
434 + wp_register_script(
435 + 'os-chromeless-bridge',
436 + OPENSTATION_URL . 'assets/js/chromeless-bridge' . $suffix . '.js',
437 + array(),
438 + $built_version( 'assets/js/chromeless-bridge' . $suffix . '.js' ),
439 + true
440 + );
441 +
442 + // `os-gutenberg-drop-receiver` — iframe-side bundle
321 443 // enqueued only on the Block Editor screens (`post.php` /
322 - // `post-new.php`) for desktop-mode users. Listens for
323 - // `desktop-mode-drop` postMessages from the parent shell (see
444 + // `post-new.php`) for openstation users. Listens for
445 + // `os-drop` postMessages from the parent shell (see
324 446 // `src/drag/iframe-drop-targets.ts`) and inserts the matching
325 447 // Gutenberg block via `wp.data.dispatch('core/block-editor')`.
326 448 // Depends on `wp-blocks` + `wp-data` so the editor stores are
327 449 // guaranteed enqueued before the receiver runs its first message
@@ -326,49 +448,32 @@
326 448 // Depends on `wp-blocks` + `wp-data` so the editor stores are
327 449 // guaranteed enqueued before the receiver runs its first message
328 450 // handler.
329 451 wp_register_script(
330 - 'desktop-mode-gutenberg-drop-receiver',
331 - DESKTOP_MODE_URL . 'assets/js/gutenberg-drop-receiver' . $suffix . '.js',
452 + 'os-gutenberg-drop-receiver',
453 + OPENSTATION_URL . 'assets/js/gutenberg-drop-receiver' . $suffix . '.js',
332 454 array( 'wp-blocks', 'wp-data' ),
333 455 $built_version( 'assets/js/gutenberg-drop-receiver' . $suffix . '.js' ),
334 456 true
335 457 );
336 458
337 - // `desktop-mode-recycle-bin` — small bundle for the Recycle Bin
338 - // native window. Lazy-loaded by the native-window sync the first
339 - // time the bin opens; registers a render callback on
340 - // `window.desktopModeNativeWindows['desktop-mode-recycle-bin']`.
341 - $recycle_bin_js = DESKTOP_MODE_DIR . 'assets/js/recycle-bin' . $suffix . '.js';
342 - wp_register_script(
343 - 'desktop-mode-recycle-bin',
344 - DESKTOP_MODE_URL . 'assets/js/recycle-bin' . $suffix . '.js',
345 - // `heartbeat` + `jquery` — the bin opts in to the WordPress
346 - // Heartbeat API while its window is open as the catch-all
347 - // real-time channel for deletes that don't render an admin
348 - // footer (REST/AJAX/other tabs/WP-CLI). See
349 - // `src/recycle-bin/realtime.ts` for the subscriber.
350 - array( 'wp-i18n', 'heartbeat', 'jquery' ),
351 - file_exists( $recycle_bin_js ) ? (string) filemtime( $recycle_bin_js ) : $version,
352 - true
353 - );
354 - wp_set_script_translations(
355 - 'desktop-mode-recycle-bin',
356 - 'desktop-mode',
357 - DESKTOP_MODE_DIR . 'languages'
358 - );
459 + // The Recycle Bin window is an App Framework app (`apps/trash/`);
460 + // its client view rides the app-bundle pipeline, so no dedicated
461 + // script handle. The `desktop-mode-recycle-bin` STYLE handle above
462 + // stays — the drag-to-trash drop-target highlight must be present
463 + // at boot (dropping on the closed bin's dock tile), not window-open.
359 464
360 465 // `desktop-mode-games` — bundle for the Games hub native window
361 466 // (launcher grid, scoreboard, challenges client). Lazy-loaded by
362 467 // the native-window sync the first time the hub opens; registers a
363 468 // render callback on
364 - // `window.desktopModeNativeWindows['desktop-mode-games']`.
469 + // `window.openStationNativeWindows['desktop-mode-games']`.
365 470 // `heartbeat` + `jquery` — the challenges client rides the
366 471 // WordPress Heartbeat bus for live delivery.
367 - $games_js = DESKTOP_MODE_DIR . 'assets/js/games' . $suffix . '.js';
472 + $games_js = OPENSTATION_DIR . 'assets/js/games' . $suffix . '.js';
368 473 wp_register_script(
369 474 'desktop-mode-games',
370 - DESKTOP_MODE_URL . 'assets/js/games' . $suffix . '.js',
475 + OPENSTATION_URL . 'assets/js/games' . $suffix . '.js',
371 476 array( 'wp-i18n', 'heartbeat', 'jquery' ),
372 477 file_exists( $games_js ) ? (string) filemtime( $games_js ) : $version,
373 478 true
374 479 );
@@ -374,120 +479,63 @@
374 479 );
375 480 wp_set_script_translations(
376 481 'desktop-mode-games',
377 482 'desktop-mode',
378 - DESKTOP_MODE_DIR . 'languages'
483 + OPENSTATION_DIR . 'languages'
379 484 );
380 485
381 - // `desktop-mode-game-inkfall` — the Inkfall game bundle. Loaded
486 + // `os-game-inkfall` — the Inkfall game bundle. Loaded
382 487 // lazily by the games framework on first launch; publishes the
383 - // game def on `window.desktopModeGames.inkfall`.
384 - $game_inkfall_js = DESKTOP_MODE_DIR . 'assets/js/game-inkfall' . $suffix . '.js';
488 + // game def on `window.openStationGames.inkfall`.
489 + $game_inkfall_js = OPENSTATION_DIR . 'assets/js/game-inkfall' . $suffix . '.js';
385 490 wp_register_script(
386 - 'desktop-mode-game-inkfall',
387 - DESKTOP_MODE_URL . 'assets/js/game-inkfall' . $suffix . '.js',
491 + 'os-game-inkfall',
492 + OPENSTATION_URL . 'assets/js/game-inkfall' . $suffix . '.js',
388 493 array( 'wp-i18n' ),
389 494 file_exists( $game_inkfall_js ) ? (string) filemtime( $game_inkfall_js ) : $version,
390 495 true
391 496 );
392 497 wp_set_script_translations(
393 - 'desktop-mode-game-inkfall',
498 + 'os-game-inkfall',
394 499 'desktop-mode',
395 - DESKTOP_MODE_DIR . 'languages'
500 + OPENSTATION_DIR . 'languages'
396 501 );
397 502
398 - // `desktop-mode-game-alphabet-soup` — the Alphabet Soup game
503 + // `os-game-alphabet-soup` — the Alphabet Soup game
399 504 // bundle. Loaded lazily by the games framework on first launch;
400 505 // publishes the game def on
401 - // `window.desktopModeGames['alphabet-soup']`.
402 - $game_alphabet_soup_js = DESKTOP_MODE_DIR . 'assets/js/game-alphabet-soup' . $suffix . '.js';
506 + // `window.openStationGames['alphabet-soup']`.
507 + $game_alphabet_soup_js = OPENSTATION_DIR . 'assets/js/game-alphabet-soup' . $suffix . '.js';
403 508 wp_register_script(
404 - 'desktop-mode-game-alphabet-soup',
405 - DESKTOP_MODE_URL . 'assets/js/game-alphabet-soup' . $suffix . '.js',
509 + 'os-game-alphabet-soup',
510 + OPENSTATION_URL . 'assets/js/game-alphabet-soup' . $suffix . '.js',
406 511 array( 'wp-i18n' ),
407 512 file_exists( $game_alphabet_soup_js ) ? (string) filemtime( $game_alphabet_soup_js ) : $version,
408 513 true
409 514 );
410 515 wp_set_script_translations(
411 - 'desktop-mode-game-alphabet-soup',
516 + 'os-game-alphabet-soup',
412 517 'desktop-mode',
413 - DESKTOP_MODE_DIR . 'languages'
518 + OPENSTATION_DIR . 'languages'
414 519 );
415 520
416 - // `desktop-mode-posts-window` — small bundle for the native Posts
417 - // window. Lazy-loaded by the native-window sync the first time the
418 - // window opens (via the dock-click swap when the user opts in);
419 - // registers a render callback on
420 - // `window.desktopModeNativeWindows['desktop-mode-posts']`.
421 - $posts_window_js = DESKTOP_MODE_DIR . 'assets/js/posts-window' . $suffix . '.js';
422 - wp_register_script(
423 - 'desktop-mode-posts-window',
424 - DESKTOP_MODE_URL . 'assets/js/posts-window' . $suffix . '.js',
425 - array( 'wp-i18n' ),
426 - file_exists( $posts_window_js ) ? (string) filemtime( $posts_window_js ) : $version,
427 - true
428 - );
429 - wp_set_script_translations(
430 - 'desktop-mode-posts-window',
431 - 'desktop-mode',
432 - DESKTOP_MODE_DIR . 'languages'
433 - );
434 -
435 - // `desktop-mode-plugins-window` — small bundle for the native
436 - // Plugins window. Lazy-loaded by the native-window sync the first
437 - // time the window opens (via the dock-click swap when the user
438 - // opts in); registers a render callback on
439 - // `window.desktopModeNativeWindows['desktop-mode-plugins']`.
440 - $plugins_window_js = DESKTOP_MODE_DIR . 'assets/js/plugins-window' . $suffix . '.js';
441 - wp_register_script(
442 - 'desktop-mode-plugins-window',
443 - DESKTOP_MODE_URL . 'assets/js/plugins-window' . $suffix . '.js',
444 - array( 'wp-i18n' ),
445 - file_exists( $plugins_window_js ) ? (string) filemtime( $plugins_window_js ) : $version,
446 - true
447 - );
448 - wp_set_script_translations(
449 - 'desktop-mode-plugins-window',
450 - 'desktop-mode',
451 - DESKTOP_MODE_DIR . 'languages'
452 - );
453 -
454 - // `desktop-mode-comments-window` — small bundle for the native
455 - // Comments window. Lazy-loaded by the native-window sync the first
456 - // time the window opens (via the dock-click swap when the user
457 - // opts in); registers a render callback on
458 - // `window.desktopModeNativeWindows['desktop-mode-comments']`.
459 - $comments_window_js = DESKTOP_MODE_DIR . 'assets/js/comments-window' . $suffix . '.js';
460 - wp_register_script(
461 - 'desktop-mode-comments-window',
462 - DESKTOP_MODE_URL . 'assets/js/comments-window' . $suffix . '.js',
463 - array( 'wp-i18n' ),
464 - file_exists( $comments_window_js ) ? (string) filemtime( $comments_window_js ) : $version,
465 - true
466 - );
467 - wp_set_script_translations(
468 - 'desktop-mode-comments-window',
469 - 'desktop-mode',
470 - DESKTOP_MODE_DIR . 'languages'
471 - );
472 -
473 - // `desktop-mode-animated-logo-wallpaper` — built-in PixiJS canvas
474 - // wallpaper, moved out of `desktop.min.js` in 0.8.4. The wallpaper
521 + // `os-animated-logo-wallpaper` — built-in PixiJS canvas
522 + // wallpaper, moved out of `desktop.min.js`. The wallpaper
475 523 // `server-sync` loads this handle when the user selects the
476 524 // `wp-animated-logo` wallpaper (or opens OS Settings → Wallpaper
477 525 // and the picker pulls every registered canvas def in). The
478 526 // bundle's only side effect is publishing the `WallpaperDef` on
479 - // `window.desktopModeWallpapers['wp-animated-logo']`.
480 - $animated_logo_js = DESKTOP_MODE_DIR . 'assets/js/animated-logo-wallpaper' . $suffix . '.js';
527 + // `window.openStationWallpapers['wp-animated-logo']`.
528 + $animated_logo_js = OPENSTATION_DIR . 'assets/js/animated-logo-wallpaper' . $suffix . '.js';
481 529 wp_register_script(
482 - 'desktop-mode-animated-logo-wallpaper',
483 - DESKTOP_MODE_URL . 'assets/js/animated-logo-wallpaper' . $suffix . '.js',
530 + 'os-animated-logo-wallpaper',
531 + OPENSTATION_URL . 'assets/js/animated-logo-wallpaper' . $suffix . '.js',
484 532 array( 'wp-hooks' ),
485 533 file_exists( $animated_logo_js ) ? (string) filemtime( $animated_logo_js ) : $version,
486 534 true
487 535 );
488 536
489 - // `desktop-mode-snow-wallpaper` — built-in PixiJS canvas
537 + // `os-snow-wallpaper` — built-in PixiJS canvas
490 538 // wallpaper: snowfall that accumulates on window tops and melts
491 539 // away. Same lazy-load path as the animated logo: the wallpaper
492 540 // `server-sync` injects this handle when the user selects the
493 541 // `wp-snow` wallpaper (or opens OS Settings → Wallpaper and the
@@ -492,32 +540,32 @@
492 540 // `server-sync` injects this handle when the user selects the
493 541 // `wp-snow` wallpaper (or opens OS Settings → Wallpaper and the
494 542 // picker pulls the def in). The bundle's only side effect is
495 543 // publishing the `WallpaperDef` on
496 - // `window.desktopModeWallpapers['wp-snow']`.
497 - $snow_js = DESKTOP_MODE_DIR . 'assets/js/snow-wallpaper' . $suffix . '.js';
544 + // `window.openStationWallpapers['wp-snow']`.
545 + $snow_js = OPENSTATION_DIR . 'assets/js/snow-wallpaper' . $suffix . '.js';
498 546 wp_register_script(
499 - 'desktop-mode-snow-wallpaper',
500 - DESKTOP_MODE_URL . 'assets/js/snow-wallpaper' . $suffix . '.js',
547 + 'os-snow-wallpaper',
548 + OPENSTATION_URL . 'assets/js/snow-wallpaper' . $suffix . '.js',
501 549 array( 'wp-hooks', 'wp-i18n' ),
502 550 file_exists( $snow_js ) ? (string) filemtime( $snow_js ) : $version,
503 551 true
504 552 );
505 553 wp_set_script_translations(
506 - 'desktop-mode-snow-wallpaper',
554 + 'os-snow-wallpaper',
507 555 'desktop-mode',
508 - DESKTOP_MODE_DIR . 'languages'
556 + OPENSTATION_DIR . 'languages'
509 557 );
510 558
511 559 // `desktop-mode-ai-assistant` — AI Copilot spotlight overlay,
512 - // moved out of `desktop.min.js` in 0.8.4. The main bundle ships a
513 - // stub matching the public `wp.desktop.ai` contract; the stub
560 + // moved out of `desktop.min.js`. The main bundle ships a
561 + // stub matching the public `wp.os.ai` contract; the stub
514 562 // `<script>`-injects this handle the first time the user opens
515 563 // the assistant (Cmd+K or admin-bar button).
516 - $ai_assistant_js = DESKTOP_MODE_DIR . 'assets/js/ai-assistant' . $suffix . '.js';
564 + $ai_assistant_js = OPENSTATION_DIR . 'assets/js/ai-assistant' . $suffix . '.js';
517 565 wp_register_script(
518 566 'desktop-mode-ai-assistant',
519 - DESKTOP_MODE_URL . 'assets/js/ai-assistant' . $suffix . '.js',
567 + OPENSTATION_URL . 'assets/js/ai-assistant' . $suffix . '.js',
520 568 array( 'wp-hooks', 'wp-i18n' ),
521 569 file_exists( $ai_assistant_js ) ? (string) filemtime( $ai_assistant_js ) : $version,
522 570 true
523 571 );
@@ -523,19 +571,19 @@
523 571 );
524 572 wp_set_script_translations(
525 573 'desktop-mode-ai-assistant',
526 574 'desktop-mode',
527 - DESKTOP_MODE_DIR . 'languages'
575 + OPENSTATION_DIR . 'languages'
528 576 );
529 577
530 578 // Wire the translation bundle to this script handle. WP looks
531 - // for `languages/desktop-mode-{locale}-desktop-mode.json` and
579 + // for `languages/os-{locale}-os.json` and
532 580 // injects its `locale_data` into `wp.i18n` just before the
533 581 // script runs — so every `__()` call resolves to the right
534 582 // language without any runtime fetch.
535 583 wp_set_script_translations(
584 + 'openstation',
536 585 'desktop-mode',
537 - 'desktop-mode',
538 - DESKTOP_MODE_DIR . 'languages'
586 + OPENSTATION_DIR . 'languages'
539 587 );
540 588 }
541 -add_action( 'init', 'desktop_mode_register_assets' );
589 +add_action( 'init', 'openstation_register_assets' );