PluginProbe
OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin / 1.1.10
OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin v1.1.10
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 0.8.9 0.8.8 0.8.7 All 34 releases
← All changes | includes/recycle-bin/window.php +43 -200 1.0.01.1.10 View file →
@@ -1,18 +1,19 @@
1 1 <?php
2 2 /**
3 - * OpenStation — Recycle Bin: window + icon registration.
3 + * OpenStation — Recycle Bin: tile art, gate, shell config.
4 4 *
5 - * Native window with id `desktop-mode-recycle-bin`, pinned to the taskbar with a
6 - * matching wallpaper icon. Like the code editor, the template body is a
7 - * static skeleton that the JS bundle enhances on first open — the table
8 - * is populated from the REST list endpoint at render time.
5 + * The bin WINDOW is an App Framework app (`apps/trash/trash.os.php`)
6 + * that claims the frozen `desktop-mode-recycle-bin` id, so every
7 + * shortcut, dock placement and drop target keeps working. This file
8 + * keeps what the shell needs regardless of the window: the two bin
9 + * drawings (the dock tile's empty/full swap — `icon-state.ts` — and
10 + * the app's own `ctx.host.setIcon()` swap read the same pair), the
11 + * capability gate, the shell-config seed that makes the tile correct
12 + * on the very first paint, and the stylesheet enqueue (the
13 + * drag-to-trash drop-target highlight must exist at boot, not at
14 + * window-open).
9 15 *
10 - * Both registrations are filterable via the standard
11 - * `openstation_recycle_bin_window_args` / `openstation_recycle_bin_icon_args`
12 - * filters so a plugin can swap the icon, change the dimensions, or
13 - * restrict who sees the bin without touching this file.
14 - *
15 16 * @package OpenStation
16 17 */
17 18
18 19 defined( 'ABSPATH' ) || exit;
@@ -17,9 +18,9 @@
17 18
18 19 defined( 'ABSPATH' ) || exit;
19 20
20 21 /**
21 - * The shared bin SVG used by the window icon and the desktop icon.
22 + * The bin SVG, used by the app window's icon and its dock tile.
22 23 *
23 24 * The bin used to be `dashicons-trash`, which worked but wore the
24 25 * wrong clothes. Dashicons are WP core's icon set: solid fills on a
25 26 * 20-unit grid, tuned for admin-menu sizes. The shell's own icons are
@@ -44,11 +45,9 @@
44 45 * are menu glyphs sitting among other menu glyphs, and they should
45 46 * match their neighbours rather than this icon.
46 47 *
47 48 * The bin has two states. Empty is the vessel on its own; full adds
48 - * three crumpled balls inside it and knocks the lid askew. See
49 - * {@link openstation_recycle_bin_icon_svg()} for why the lid only
50 - * moves 8 degrees.
49 + * three crumpled balls inside it and knocks the lid askew.
51 50 *
52 51 * @param bool $full Whether to draw the bin holding something.
53 52 * @return string Raw `<svg>` markup.
54 53 */
@@ -53,12 +52,20 @@
53 52 * @return string Raw `<svg>` markup.
54 53 */
55 54 function openstation_recycle_bin_icon_svg( $full = false ) {
56 55 // The lid and the handle travel together. In the full state the
57 - // pair is knocked askew, which is the whole difference at the top
58 - // of the mark.
56 + // pair is lifted clear of the rim and tipped, hinged at the far
57 + // corner, the way a lid sits on a bin that has too much in it.
58 + //
59 + // It was a 2.5-unit lift at 8 degrees, which on the 20px dock
60 + // tile and the 58px home tile was no difference at all: the bin
61 + // read as empty while it held things. At 4 units and 12 degrees
62 + // (a positive angle turns clockwise about the far corner, so the
63 + // near end rises) the lid's near end clears the rim by a fifth
64 + // of the body's height and its far end by nine units, and the
65 + // wedge of light under it survives every size the mark is drawn.
59 66 $lid_transform = $full
60 - ? ' transform="translate(0 -2.5) rotate(8 32 21.5)"'
67 + ? ' transform="translate(0 -4) rotate(12 52 21.5)"'
61 68 : '';
62 69
63 70 $svg = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">'
64 71 . '<g' . $lid_transform . '>'
@@ -101,8 +108,16 @@
101 108 $svg .= '<path d="M29.7 38 27.4 39.5 24.7 39.6 23.6 37.1 24.1 34.4 26.8 34.1 29.2 35.1'
102 109 . 'ZM39.4 44.1 36.7 43.5 34.8 41.6 35.8 39.1 38.1 37.6 40.2 39.3 41.1 41.8'
103 110 . 'ZM28.1 50.4 27 47.9 27.4 45.2 30 44.6 32.6 45.6 32.4 48.3 31 50.5Z"'
104 111 . ' fill="currentColor" stroke="currentColor" stroke-width="1.2" stroke-linejoin="round"/>';
112 + // A fourth, larger sheet rides the rim under the lifted end of
113 + // the lid — the one element of the full state that is legible
114 + // at 20px, where the balls inside the body are a texture at
115 + // best. Same seven-point construction, twice the radius,
116 + // straddling the rim (y 28.5) so it reads as spilling out
117 + // rather than sitting in.
118 + $svg .= '<path d="M30 26 27.3 30 22.7 31.7 19.5 28.2 18.6 23.4 22.8 20.7 27.6 21.6Z"'
119 + . ' fill="currentColor" stroke="currentColor" stroke-width="1.2" stroke-linejoin="round"/>';
105 120 }
106 121
107 122 return $svg . '</svg>';
108 123 }
@@ -123,114 +138,13 @@
123 138 );
124 139 }
125 140
126 141 /**
127 - * Echoes the recycle bin window's template body.
128 - *
129 - * The shell wraps this in `<template id="os-native-window-desktop-mode-recycle-bin">`
130 - * and clones it into the window body BEFORE the JS render callback runs.
131 - * The `data-os-recycle-bin-*` hooks below are the contract the JS
132 - * relies on — keep them intact (or rename via the filter) when
133 - * customizing the layout.
134 - */
135 -function openstation_recycle_bin_render_template() {
136 - ob_start();
137 - ?>
138 - <div class="desktop-mode-recycle-bin" data-os-recycle-bin-root>
139 - <header class="os-recycle-bin__toolbar" data-os-recycle-bin-toolbar>
140 - <div class="os-recycle-bin__toolbar-left">
141 - <os-segmented data-os-recycle-bin-filter>
142 - <os-segment value="" selected><?php esc_html_e( 'All', 'desktop-mode' ); ?></os-segment>
143 - <os-segment value="post"><?php esc_html_e( 'Posts', 'desktop-mode' ); ?></os-segment>
144 - <os-segment value="page"><?php esc_html_e( 'Pages', 'desktop-mode' ); ?></os-segment>
145 - <?php
146 - // The Media segment is only useful when WP itself routes
147 - // attachment deletions through Trash. That gate is the
148 - // `MEDIA_TRASH` constant — defaults to false in core, can
149 - // be flipped to true from `wp-config.php`. Without it,
150 - // attachments permanent-delete on first click and the
151 - // Trash bin will never have anything in this bucket, so
152 - // the tab would always read "0" and confuse users.
153 - if ( defined( 'MEDIA_TRASH' ) && MEDIA_TRASH ) :
154 - ?>
155 - <os-segment value="attachment"><?php esc_html_e( 'Media', 'desktop-mode' ); ?></os-segment>
156 - <?php
157 - endif;
158 - ?>
159 - <os-segment value="comment"><?php esc_html_e( 'Comments', 'desktop-mode' ); ?></os-segment>
160 - <os-segment value="desktop"><?php esc_html_e( 'Desktop', 'desktop-mode' ); ?></os-segment>
161 - </os-segmented>
162 - <os-text-field
163 - data-os-recycle-bin-search
164 - placeholder="<?php esc_attr_e( 'Search trash…', 'desktop-mode' ); ?>"
165 - ></os-text-field>
166 - </div>
167 - <div class="os-recycle-bin__toolbar-right" data-os-recycle-bin-bulk hidden>
168 - <span class="os-recycle-bin__count" data-os-recycle-bin-count></span>
169 - <os-button variant="secondary" data-os-recycle-bin-restore-selected>
170 - <span class="dashicons dashicons-image-rotate" aria-hidden="true"></span>
171 - <?php esc_html_e( 'Restore', 'desktop-mode' ); ?>
172 - </os-button>
173 - <os-button variant="secondary" data-os-recycle-bin-pin-to-desktop>
174 - <span class="dashicons dashicons-desktop" aria-hidden="true"></span>
175 - <?php esc_html_e( 'Pin to desktop', 'desktop-mode' ); ?>
176 - </os-button>
177 - <os-button variant="danger" data-os-recycle-bin-purge-selected>
178 - <span class="dashicons dashicons-trash" aria-hidden="true"></span>
179 - <?php esc_html_e( 'Delete forever', 'desktop-mode' ); ?>
180 - </os-button>
181 - </div>
182 - <div class="os-recycle-bin__toolbar-trailing">
183 - <os-button variant="ghost" data-os-recycle-bin-refresh title="<?php esc_attr_e( 'Refresh', 'desktop-mode' ); ?>">
184 - <span class="dashicons dashicons-update" aria-hidden="true"></span>
185 - </os-button>
186 - <os-button variant="danger" data-os-recycle-bin-empty>
187 - <span class="dashicons dashicons-trash" aria-hidden="true"></span>
188 - <?php esc_html_e( 'Empty Trash', 'desktop-mode' ); ?>
189 - </os-button>
190 - </div>
191 - </header>
192 - <div class="os-recycle-bin__body" data-os-recycle-bin-body>
193 - <os-table
194 - data-os-recycle-bin-table
195 - selectable="multi"
196 - sticky-header
197 - hover
198 - striped
199 - loading
200 - >
201 - <div slot="empty" class="os-recycle-bin__empty">
202 - <span class="dashicons dashicons-trash" aria-hidden="true"></span>
203 - <p><?php esc_html_e( 'The Trash is empty.', 'desktop-mode' ); ?></p>
204 - <p class="os-recycle-bin__empty-hint">
205 - <?php esc_html_e( 'Deleted posts, pages, and media show up here. Restoring puts them back where they were.', 'desktop-mode' ); ?>
206 - </p>
207 - </div>
208 - </os-table>
209 - </div>
210 - </div>
211 - <?php
212 - $html = (string) ob_get_clean();
213 -
214 - /**
215 - * Filter the recycle bin window's template HTML.
216 - *
217 - * Keep the `data-os-recycle-bin-*` hooks intact so the JS render
218 - * callback can find its mount points, or rename them and update the
219 - * matching constants in `src/recycle-bin/index.ts`.
220 - *
221 - * @param string $html Default template HTML.
222 - */
223 - $filtered = (string) apply_filters( 'openstation_recycle_bin_template_html', $html );
224 - echo wp_kses( $filtered, openstation_native_window_allowed_html() );
225 -}
226 -
227 -/**
228 142 * Whether the current user should see the recycle bin at all.
229 143 *
230 144 * Filterable so plugins can hide it from authors/contributors who
231 145 * don't manage trash, or invert the gate to expose it to a custom
232 - * role.
146 + * role. The app's gate (`apps/trash/trash.os.php`) delegates here.
233 147 *
234 148 * @return bool
235 149 */
236 150 function openstation_recycle_bin_user_can_use() {
@@ -244,99 +158,28 @@
244 158 return (bool) apply_filters( 'openstation_recycle_bin_user_can_use', $can );
245 159 }
246 160
247 161 /**
248 - * Register the recycle bin window + desktop icon on `init`.
162 + * Enqueue the bin stylesheet with the shell.
249 163 *
250 - * Hooked at priority 20, after `components.php` has bootstrapped the
251 - * native-window registry — same timing as the code editor.
164 + * Not a window-open companion: the sheet also paints the
165 + * drag-to-trash drop-target highlight on the CLOSED bin's dock tile
166 + * (`data-os-trash-drop-active`), which must work before the window
167 + * has ever opened.
252 168 */
253 -function openstation_recycle_bin_register_window() {
169 +function openstation_recycle_bin_enqueue_style() {
254 170 if ( ! openstation_recycle_bin_user_can_use() ) {
255 171 return;
256 172 }
257 -
258 - $icon_uris = openstation_recycle_bin_icon_uris();
259 - $icon_uri = $icon_uris['empty'];
260 -
261 - $window_args = array(
262 - 'title' => __( 'Trash', 'desktop-mode' ),
263 - 'icon' => $icon_uri,
264 - 'template' => 'openstation_recycle_bin_render_template',
265 - 'script' => 'desktop-mode-recycle-bin',
266 - 'width' => 880,
267 - 'height' => 560,
268 - 'min_width' => 520,
269 - 'min_height' => 360,
270 - 'placement' => 'taskbar',
271 - );
272 -
273 - /**
274 - * Filter the args used to register the recycle bin native window.
275 - *
276 - * @param array $window_args Args passed to `openstation_register_window()`.
277 - */
278 - $window_args = (array) apply_filters( 'openstation_recycle_bin_window_args', $window_args );
279 -
280 - $registered = openstation_register_window( 'desktop-mode-recycle-bin', $window_args );
281 - if ( is_wp_error( $registered ) ) {
282 - // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log
283 - error_log( '[openstation] Recycle bin window registration failed: ' . $registered->get_error_message() );
284 - return;
285 - }
286 -
287 - $icon_args = array(
288 - 'title' => __( 'Trash', 'desktop-mode' ),
289 - 'icon_svg' => openstation_recycle_bin_icon_svg(),
290 - 'window' => 'desktop-mode-recycle-bin',
291 - 'position' => 80,
292 - );
293 -
294 - /**
295 - * Filter the args used to register the recycle bin desktop icon.
296 - *
297 - * @param array $icon_args Args passed to `openstation_register_icon()`.
298 - */
299 - $icon_args = (array) apply_filters( 'openstation_recycle_bin_icon_args', $icon_args );
300 -
301 - openstation_register_icon( 'desktop-mode-recycle-bin', $icon_args );
302 -}
303 -add_action( 'init', 'openstation_recycle_bin_register_window', 20 );
304 -
305 -/**
306 - * Localize REST endpoints for the JS bundle.
307 - *
308 - * Same pattern as the code editor: the bundle reads its config off
309 - * `window.openStationRecycleBinConfig` and never hardcodes URLs.
310 - */
311 -function openstation_recycle_bin_localize_config() {
312 - if ( ! openstation_recycle_bin_user_can_use() ) {
313 - return;
314 - }
315 -
316 - wp_localize_script(
317 - 'desktop-mode-recycle-bin',
318 - 'openStationRecycleBinConfig',
319 - array(
320 - 'restNonce' => wp_create_nonce( 'wp_rest' ),
321 - 'listUrl' => esc_url_raw( rest_url( 'desktop-mode/v1/recycle-bin' ) ),
322 - 'restoreUrl' => esc_url_raw( rest_url( 'desktop-mode/v1/recycle-bin/restore' ) ),
323 - 'purgeUrl' => esc_url_raw( rest_url( 'desktop-mode/v1/recycle-bin/purge' ) ),
324 - 'emptyUrl' => esc_url_raw( rest_url( 'desktop-mode/v1/recycle-bin/empty' ) ),
325 - 'countUrl' => esc_url_raw( rest_url( 'desktop-mode/v1/recycle-bin/count' ) ),
326 - 'postTypes' => openstation_recycle_bin_capture_post_types(),
327 - )
328 - );
329 -
330 173 wp_enqueue_style( 'desktop-mode-recycle-bin' );
331 174 }
332 -add_action( 'admin_enqueue_scripts', 'openstation_recycle_bin_localize_config', 30 );
175 +add_action( 'admin_enqueue_scripts', 'openstation_recycle_bin_enqueue_style', 5 );
333 176
334 177 /**
335 178 * Inject the initial trash count and both bin drawings into the
336 - * shell config, so the dock/taskbar tile and the desktop icon show
337 - * the right one on the very first paint, before the bin window has
338 - * ever opened.
179 + * shell config, so the dock tile (and any icon a user or plugin has
180 + * placed against this window) shows the right one on the very first
181 + * paint, before the bin window has ever opened.
339 182 *
340 183 * Both drawings travel together rather than the server picking one:
341 184 * the count changes without a reload, and shipping the pair makes
342 185 * crossing zero a local swap instead of a round trip.