# desktop-mode/0.9.3/assets/js/admin-bar.js

OpenStation: Desktop Windows, Dock &amp; Virtual Desktops for WP Admin, version 0.9.3. 462 lines.

- Page: https://pluginprobe.com/plugins/desktop-mode/0.9.3/code/assets/js/admin-bar.js
- Raw: https://pluginprobe.com/plugins/desktop-mode/0.9.3/raw/assets/js/admin-bar.js
- Modified: 2026-05-19T16:14:48+00:00

Line numbers below start at 1. Link to a line or a range by appending a fragment to the
page URL, for example `https://pluginprobe.com/plugins/desktop-mode/0.9.3/code/assets/js/admin-bar.js#L10-L20`.

```javascript
( function() {
	var toggle = document.getElementById( 'wp-admin-bar-desktop-mode-toggle' );
	if ( ! toggle ) {
		return;
	}
	var cfg = window.desktopModeAdminBar || {};
	toggle.addEventListener( 'click', function( e ) {
		e.preventDefault();
		var isActive = !! cfg.active;
		var newValue = isActive ? '' : '1';
		// Fallback targets if the server response is missing a `redirect`
		// field (shouldn't happen, but keep the click functional either
		// way). Disabling -> classic admin (NOT the portal, which would
		// auto-re-enable); enabling -> portal URL so the shell takes over.
		var fallback = isActive ? cfg.classicUrl : cfg.portalUrl;
		// The toggle lives in an admin bar that may be rendered either in
		// the top window (classic) or — today it's suppressed in iframes,
		// but a plugin could surface it — inside a chromeless iframe. In
		// either case we want the ENTIRE browser tab to navigate, so we
		// hit `window.top` and fall back to `window` if cross-origin
		// security blocks access.
		function navigate( url ) {
			try {
				window.top.location.href = url;
			} catch ( err ) {
				window.location.href = url;
			}
		}
		var body = new URLSearchParams();
		body.set( 'action', 'save-desktop-mode' );
		body.set( 'nonce', cfg.nonce );
		body.set( 'enabled', newValue );
		var xhr = new XMLHttpRequest();
		xhr.open( 'POST', cfg.ajaxUrl, true );
		xhr.setRequestHeader( 'Content-Type', 'application/x-www-form-urlencoded' );
		xhr.onload = function() {
			if ( xhr.status !== 200 ) {
				return;
			}
			var target = fallback;
			try {
				var resp = JSON.parse( xhr.responseText );
				if ( resp && resp.success && resp.data && resp.data.redirect ) {
					target = resp.data.redirect;
				}
			} catch ( parseErr ) {}
			navigate( target );
		};
		xhr.send( body.toString() );
	} );

	// Layout menu — each child item calls a WindowManager method on
	// the public shell API. We bind one delegated click listener on
	// the parent submenu so adding more layouts in the future
	// (split, full-width, etc.) is a matter of adding nodes in PHP,
	// not new JS. `href=#` is set server-side; we preventDefault +
	// intercept.
	//
	// The snap-to-grid checkbox is special: clicking it toggles the
	// preference AND repaints the box without dismissing the menu
	// (default WP behaviour would close the submenu on any click,
	// breaking the "set it and forget it" feel of a checkbox).
	var layoutMenu = document.getElementById( 'wp-admin-bar-desktop-layout-menu' );
	if ( ! layoutMenu ) return;

	function paintSnapCheckbox( enabled ) {
		var node = document.querySelector(
			'#wp-admin-bar-desktop-layout-snap .desktop-mode-layout-checkbox'
		);
		if ( ! node ) return;
		node.textContent = enabled ? '☑' : '☐'; // ☑ / ☐
		var item = document.getElementById( 'wp-admin-bar-desktop-layout-snap' );
		if ( item ) {
			item.setAttribute( 'aria-checked', enabled ? 'true' : 'false' );
			item.setAttribute( 'role', 'menuitemcheckbox' );
		}
	}

	function getManager() {
		return window.wp && window.wp.desktop && window.wp.desktop.windowManager;
	}

	// Initial paint — wait for the shell to publish the manager,
	// then mirror the persisted snap preference. Polled rather than
	// hooked because the inline script ships with the admin bar
	// (loads early) and the shell's WindowManager arrives later.
	function initFromManager() {
		var wm = getManager();
		if ( ! wm || typeof wm.isSnapEnabled !== 'function' ) {
			window.setTimeout( initFromManager, 60 );
			return;
		}
		paintSnapCheckbox( wm.isSnapEnabled() );
	}
	initFromManager();

	layoutMenu.addEventListener( 'click', function( e ) {
		var t = e.target;
		if ( ! t || ! t.closest ) return;

		var snapItem = t.closest( '.desktop-mode-layout-snap' );
		if ( snapItem ) {
			// Stop propagation so WP's own "click closes submenu"
			// chain never fires. preventDefault keeps the `#` href
			// from scrolling the page to top.
			e.preventDefault();
			e.stopPropagation();
			var wm = getManager();
			if ( ! wm || typeof wm.setSnapEnabled !== 'function' ) return;
			var next = ! wm.isSnapEnabled();
			wm.setSnapEnabled( next );
			paintSnapCheckbox( next );
			return;
		}

		var actionLink = t.closest( '.desktop-mode-layout-action > .ab-item, .desktop-mode-layout-action' );
		if ( ! actionLink ) return;
		e.preventDefault();
		var id = actionLink.closest( '[id^="wp-admin-bar-desktop-layout-"]' );
		if ( ! id ) return;
		var manager = getManager();
		if ( ! manager ) return;
		if ( id.id === 'wp-admin-bar-desktop-layout-cascade' && typeof manager.cascade === 'function' ) {
			manager.cascade();
		} else if ( id.id === 'wp-admin-bar-desktop-layout-overview' && typeof manager.enterOverview === 'function' ) {
			manager.enterOverview();
		} else if ( id.id === 'wp-admin-bar-desktop-layout-tile' && typeof manager.tile === 'function' ) {
			manager.tile();
		} else if ( id.id.indexOf( 'wp-admin-bar-desktop-layout-custom-' ) === 0 ) {
			// Plugin-registered custom item. Strip the shared prefix to
			// recover the `id` the plugin supplied via the PHP filter,
			// then dispatch the public JS action. Plugins subscribe
			// via wp.hooks.addAction( 'desktop-mode.arrange.custom-action', ... ).
			var customId = id.id.replace( 'wp-admin-bar-desktop-layout-custom-', '' );
			var hooks = window.wp && window.wp.hooks;
			if ( hooks && typeof hooks.doAction === 'function' ) {
				hooks.doAction( 'desktop-mode.arrange.custom-action', { id: customId } );
			}
		}
		// After running an action, dismiss the submenu so the user
		// lands in the newly arranged desktop instead of the menu
		// hanging open on top. WP's admin bar toggles visibility via
		// a `.hover` class on the parent `li.menupop` — we remove it
		// AND blur the active element so a re-hover is required for
		// the next open. The snap checkbox stays open by design
		// (it's handled by the earlier branch and never reaches
		// this close path).
		layoutMenu.classList.remove( 'hover' );
		if ( document.activeElement && typeof document.activeElement.blur === 'function' ) {
			document.activeElement.blur();
		}
	} );

	// AI Assistant button — dispatches the `desktop-mode-open-ai` event that
	// the AiAssistant class listens for. Using an event instead of a direct
	// call decouples the admin-bar inline script (which runs early, before
	// the desktop shell has initialised) from the AiAssistant instance.
	var aiBtn = document.getElementById( 'wp-admin-bar-desktop-ai-assistant' );
	if ( aiBtn ) {
		aiBtn.addEventListener( 'click', function( e ) {
			e.preventDefault();
			document.dispatchEvent( new CustomEvent( 'desktop-mode-open-ai' ) );
		} );
	}

	// Fullscreen button — toggles browser fullscreen on the document
	// element so the shell occupies the whole screen with no browser
	// chrome. The click counts as a user gesture, which is required by
	// the Fullscreen API. We listen for `fullscreenchange` instead of
	// flipping state inside the click handler because the user can also
	// exit via Esc or the OS, and we want the icon/label to stay in sync
	// in those cases too.
	var fsBtn = document.getElementById( 'wp-admin-bar-desktop-fullscreen' );
	if ( fsBtn ) {
		var fsLink = fsBtn.querySelector( '.ab-item' );
		var fsLabel = fsBtn.querySelector( '.ab-label' );
		var fsI18n = ( cfg && cfg.i18n ) || {};
		// WP renders admin-bar items as `<a href="#">`, which HTML5
		// marks implicitly draggable. In browser fullscreen the button
		// sits at top:0 where cursor reveals (menu bar, exit
		// affordance) produce enough pointer jitter between mousedown
		// and mouseup that the browser commits to a native link-drag
		// instead of a click — the handler never runs and the user
		// sees a ghost flicker. Opt the element out of native drag so
		// the click always lands.
		if ( fsLink ) {
			fsLink.setAttribute( 'draggable', 'false' );
		}
		function paintFullscreen( on ) {
			// Body class drives the CSS that hides admin-bar items
			// which sit too close to the screen-corner reveal hot zones
			// in browser fullscreen — the OS / browser intercept clicks
			// in those bands. Hiding them shifts the Fullscreen button
			// further from the right edge so its own click lands.
			document.body.classList.toggle( 'desktop-mode-browser-fs', !! on );
			if ( on ) {
				fsBtn.classList.add( 'is-fullscreen' );
				if ( fsLabel ) fsLabel.textContent = fsI18n.exitFullscreen || 'Exit fullscreen';
				if ( fsLink ) fsLink.setAttribute( 'title', fsI18n.exitTitle || 'Exit fullscreen' );
			} else {
				fsBtn.classList.remove( 'is-fullscreen' );
				if ( fsLabel ) fsLabel.textContent = fsI18n.enterFullscreen || 'Fullscreen';
				if ( fsLink ) fsLink.setAttribute( 'title', fsI18n.enterTitle || 'Enter fullscreen' );
			}
		}
		fsBtn.addEventListener( 'click', function( e ) {
			e.preventDefault();
			// `window.top` so the whole tab goes fullscreen even when the
			// admin bar happens to be rendered inside an iframe (today
			// it's suppressed there, but a plugin could surface it). Fall
			// back to the current document if cross-origin blocks access.
			var doc;
			try {
				doc = window.top.document;
			} catch ( err ) {
				doc = document;
			}
			if ( doc.fullscreenElement ) {
				if ( doc.exitFullscreen ) {
					doc.exitFullscreen();
				}
			} else if ( doc.documentElement && doc.documentElement.requestFullscreen ) {
				doc.documentElement.requestFullscreen();
			}
		} );
		// Listen on whichever document we're driving so OS/Esc exits
		// repaint the button too. Bound on both to cover the iframe edge
		// case without extra branching.
		document.addEventListener( 'fullscreenchange', function() {
			paintFullscreen( !! document.fullscreenElement );
		} );
		try {
			if ( window.top.document !== document ) {
				window.top.document.addEventListener( 'fullscreenchange', function() {
					paintFullscreen( !! window.top.document.fullscreenElement );
				} );
			}
		} catch ( err ) {}
	}

	// Bug Report button — same decoupling pattern as Ask AI. Dispatches
	// `desktop-mode-open-bug-report`; the shell answers by opening the
	// Bug Report native window. Wired in `src/desktop.ts`.
	var bugBtn = document.getElementById( 'wp-admin-bar-desktop-bug-report' );
	if ( bugBtn ) {
		bugBtn.addEventListener( 'click', function( e ) {
			e.preventDefault();
			document.dispatchEvent( new CustomEvent( 'desktop-mode-open-bug-report' ) );
		} );
	}

	// Keyboard Shortcuts button — toggles a floating popover anchored
	// under the button, styled like the Arrange submenu. Content is
	// passed in via `cfg.shortcuts` (translated server-side in PHP).
	wireShortcutsPopover( document.getElementById( 'wp-admin-bar-desktop-help' ), cfg.shortcuts );

	// Custom tooltips for the icon-only admin-bar buttons. The native
	// `title` attribute renders a slow, OS-styled tooltip that conflicts
	// with our dock-style custom tooltip; we swap each `title` to
	// `data-desktop-tooltip` + `aria-label` so screen readers still see
	// the label but the visual tooltip is fully ours.
	wireTooltipsFor( [
		'wp-admin-bar-desktop-fullscreen',
		'wp-admin-bar-desktop-help',
		'wp-admin-bar-desktop-bug-report',
		'wp-admin-bar-desktop-layout-menu',
	] );

	/**
	 * Re-anchors a native `title` attribute to a `data-desktop-tooltip`
	 * data attribute on the same node, plus mirrors it to `aria-label`
	 * so assistive tech keeps the description. Pure-CSS tooltip then
	 * renders from the data attribute via the `[data-desktop-tooltip]
	 * .ab-item::after` rule in admin-bar.php.
	 */
	function wireTooltipsFor( ids ) {
		for ( var i = 0; i < ids.length; i++ ) {
			var node = document.getElementById( ids[ i ] );
			if ( ! node ) continue;
			var link = node.querySelector( '.ab-item' );
			if ( ! link ) continue;
			var label = link.getAttribute( 'title' );
			if ( ! label ) continue;
			link.removeAttribute( 'title' );
			link.setAttribute( 'data-desktop-tooltip', label );
			if ( ! link.hasAttribute( 'aria-label' ) ) {
				link.setAttribute( 'aria-label', label );
			}
		}
	}

	function wireShortcutsPopover( btn, data ) {
		if ( ! btn || ! data ) {
			return;
		}
		var anchor = btn.querySelector( '.ab-item' ) || btn;
		var popover = buildShortcutsPopover( data );
		btn.appendChild( popover );

		var isOpen = false;
		function open() {
			if ( isOpen ) return;
			isOpen = true;
			popover.classList.add( 'is-open' );
			btn.classList.add( 'is-open' );
			document.addEventListener( 'mousedown', onDocMouseDown, true );
			document.addEventListener( 'keydown', onKey, true );
		}
		function close() {
			if ( ! isOpen ) return;
			isOpen = false;
			popover.classList.remove( 'is-open' );
			btn.classList.remove( 'is-open' );
			document.removeEventListener( 'mousedown', onDocMouseDown, true );
			document.removeEventListener( 'keydown', onKey, true );
		}
		function onDocMouseDown( e ) {
			if ( btn.contains( e.target ) ) return;
			close();
		}
		function onKey( e ) {
			if ( e.key === 'Escape' ) {
				e.stopPropagation();
				close();
			}
		}

		anchor.addEventListener( 'click', function( e ) {
			e.preventDefault();
			e.stopPropagation();
			isOpen ? close() : open();
		} );
		// Swallow stray clicks inside the popover so they don't bubble
		// up to admin-bar handlers (and so the popover stays open while
		// the user reads it).
		popover.addEventListener( 'mousedown', function( e ) {
			e.stopPropagation();
		} );
		popover.addEventListener( 'click', function( e ) {
			e.stopPropagation();
		} );
	}

	function buildShortcutsPopover( data ) {
		var root = document.createElement( 'div' );
		root.className = 'desktop-mode-shortcuts-popover';
		root.setAttribute( 'role', 'dialog' );
		if ( data.title ) {
			root.setAttribute( 'aria-label', data.title );
		}

		if ( data.contextual ) {
			root.appendChild( buildShortcutsTable( data.contextual ) );
		}
		if ( data.general ) {
			root.appendChild( buildShortcutsList( data.general ) );
		}
		return root;
	}

	function buildShortcutsTable( section ) {
		var wrap = document.createElement( 'section' );
		wrap.className = 'desktop-mode-shortcuts-popover__section';

		if ( section.heading ) {
			var h = document.createElement( 'h3' );
			h.className = 'desktop-mode-shortcuts-popover__heading';
			h.textContent = section.heading;
			wrap.appendChild( h );
		}

		var table = document.createElement( 'table' );
		table.className = 'desktop-mode-shortcuts-popover__table';

		var thead = document.createElement( 'thead' );
		var headRow = document.createElement( 'tr' );
		[ 'key', 'outside', 'inside', 'showDesktop' ].forEach( function( col ) {
			var th = document.createElement( 'th' );
			th.scope = 'col';
			th.textContent = section.headers && section.headers[ col ] ? section.headers[ col ] : '';
			headRow.appendChild( th );
		} );
		thead.appendChild( headRow );
		table.appendChild( thead );

		var tbody = document.createElement( 'tbody' );
		( section.rows || [] ).forEach( function( row ) {
			var tr = document.createElement( 'tr' );

			var keyCell = document.createElement( 'td' );
			keyCell.className = 'desktop-mode-shortcuts-popover__key-cell';
			keyCell.appendChild( renderKeys( row.keys || [] ) );
			if ( row.note ) {
				var note = document.createElement( 'span' );
				note.className = 'desktop-mode-shortcuts-popover__note';
				note.textContent = ' ' + row.note;
				keyCell.appendChild( note );
			}
			tr.appendChild( keyCell );

			[ 'outside', 'inside', 'showDesktop' ].forEach( function( col ) {
				var td = document.createElement( 'td' );
				td.textContent = row[ col ] || '—';
				tr.appendChild( td );
			} );

			tbody.appendChild( tr );
		} );
		table.appendChild( tbody );
		wrap.appendChild( table );

		return wrap;
	}

	function buildShortcutsList( section ) {
		var wrap = document.createElement( 'section' );
		wrap.className = 'desktop-mode-shortcuts-popover__section';

		if ( section.heading ) {
			var h = document.createElement( 'h3' );
			h.className = 'desktop-mode-shortcuts-popover__heading';
			h.textContent = section.heading;
			wrap.appendChild( h );
		}

		var list = document.createElement( 'ul' );
		list.className = 'desktop-mode-shortcuts-popover__list';
		( section.items || [] ).forEach( function( item ) {
			var li = document.createElement( 'li' );
			li.className = 'desktop-mode-shortcuts-popover__item';
			li.appendChild( renderKeys( item.keys || [] ) );
			var desc = document.createElement( 'span' );
			desc.className = 'desktop-mode-shortcuts-popover__description';
			desc.textContent = item.description || '';
			li.appendChild( desc );
			list.appendChild( li );
		} );
		wrap.appendChild( list );

		return wrap;
	}

	function renderKeys( keys ) {
		var span = document.createElement( 'span' );
		span.className = 'desktop-mode-shortcuts-popover__keys';
		keys.forEach( function( key, idx ) {
			if ( idx > 0 ) {
				var plus = document.createElement( 'span' );
				plus.className = 'desktop-mode-shortcuts-popover__plus';
				plus.textContent = '+';
				plus.setAttribute( 'aria-hidden', 'true' );
				span.appendChild( plus );
			}
			var kbd = document.createElement( 'kbd' );
			kbd.className = 'desktop-mode-shortcuts-popover__kbd';
			kbd.textContent = key;
			span.appendChild( kbd );
		} );
		return span;
	}
} )();

```
