feat: add FLYOUT_MENU_MAP data map and _buildFlyoutMenuItems builder
This commit is contained in:
@@ -139,6 +139,82 @@ let _flyoutSessionKey = null;
|
||||
let _flyoutSessionName = null;
|
||||
let _flyoutRemoteId = null;
|
||||
|
||||
/**
|
||||
* Data map of menu item definitions keyed by view type.
|
||||
* Each entry is an array of item config objects with:
|
||||
* { label, action, className?, separator? }
|
||||
* The 'user' view type gets the active view name injected at render time.
|
||||
*/
|
||||
var FLYOUT_MENU_MAP = {
|
||||
'all': [
|
||||
{ label: 'Add to View\u2026', action: 'add-to-view', className: 'flyout-menu__item--has-submenu' },
|
||||
{ label: 'Hide', action: 'hide' },
|
||||
{ separator: true },
|
||||
{ label: 'Kill Session', action: 'kill', className: 'flyout-menu__item--danger' },
|
||||
],
|
||||
'user': [
|
||||
{ label: 'Add to View\u2026', action: 'add-to-view', className: 'flyout-menu__item--has-submenu' },
|
||||
{ label: 'Remove from {viewName}', action: 'remove-from-view' },
|
||||
{ label: 'Hide', action: 'hide' },
|
||||
{ separator: true },
|
||||
{ label: 'Kill Session', action: 'kill', className: 'flyout-menu__item--danger' },
|
||||
],
|
||||
'hidden': [
|
||||
{ label: 'Unhide', action: 'unhide' },
|
||||
{ label: 'Unhide & Add to View\u2026', action: 'unhide-add-to-view', className: 'flyout-menu__item--has-submenu' },
|
||||
{ separator: true },
|
||||
{ label: 'Kill Session', action: 'kill', className: 'flyout-menu__item--danger' },
|
||||
],
|
||||
};
|
||||
|
||||
/**
|
||||
* Build the flyout menu HTML string based on the active view type.
|
||||
* Uses FLYOUT_MENU_MAP to generate items — no if/else chains.
|
||||
* @returns {string} HTML for the menu items
|
||||
*/
|
||||
function _buildFlyoutMenuItems() {
|
||||
// Determine view type: 'all', 'hidden', or 'user'
|
||||
var viewType = _activeView;
|
||||
if (viewType !== 'all' && viewType !== 'hidden') {
|
||||
viewType = 'user';
|
||||
}
|
||||
|
||||
var items = FLYOUT_MENU_MAP[viewType] || FLYOUT_MENU_MAP['all'];
|
||||
var html = '';
|
||||
|
||||
for (var i = 0; i < items.length; i++) {
|
||||
var item = items[i];
|
||||
if (item.separator) {
|
||||
html += '<div class="flyout-menu__separator" role="separator"></div>';
|
||||
continue;
|
||||
}
|
||||
|
||||
var label = item.label;
|
||||
// Inject view name for "Remove from {viewName}"
|
||||
if (label.indexOf('{viewName}') !== -1) {
|
||||
var displayName = _activeView;
|
||||
if (displayName.length > 20) {
|
||||
displayName = displayName.substring(0, 20) + '\u2026';
|
||||
}
|
||||
label = label.replace('{viewName}', escapeHtml(displayName));
|
||||
}
|
||||
|
||||
var cls = 'flyout-menu__item';
|
||||
if (item.className) cls += ' ' + item.className;
|
||||
|
||||
var titleAttr = '';
|
||||
if (item.action === 'remove-from-view' && _activeView && _activeView.length > 20) {
|
||||
titleAttr = ' title="Remove from ' + escapeHtml(_activeView) + '"';
|
||||
}
|
||||
|
||||
html += '<button class="' + cls + '" role="menuitem" data-action="' + item.action + '"' + titleAttr + '>';
|
||||
html += label;
|
||||
html += '</button>';
|
||||
}
|
||||
|
||||
return html;
|
||||
}
|
||||
|
||||
// ─── Settings state ───────────────────────────────────────────────────────────
|
||||
let _settingsOpen = false;
|
||||
let _serverSettings = null;
|
||||
|
||||
@@ -3748,3 +3748,43 @@ def test_old_tile_delete_handler_removed() -> None:
|
||||
assert "tile-delete" not in bind_body, (
|
||||
"The old .tile-delete delegated handler must be removed from bindStaticEventListeners"
|
||||
)
|
||||
|
||||
|
||||
# ─── Task 4: Context-dependent menu items — FLYOUT_MENU_MAP ──────────────────
|
||||
|
||||
|
||||
def test_flyout_menu_map_exists() -> None:
|
||||
"""app.js must define a FLYOUT_MENU_MAP data structure."""
|
||||
assert "FLYOUT_MENU_MAP" in _JS, (
|
||||
"app.js must contain a FLYOUT_MENU_MAP data structure"
|
||||
)
|
||||
|
||||
|
||||
def test_flyout_menu_map_has_three_view_types() -> None:
|
||||
"""FLYOUT_MENU_MAP must have keys for 'all', 'user', and 'hidden'."""
|
||||
# The map should reference all three view types
|
||||
map_section = _JS.split("FLYOUT_MENU_MAP")[1].split("};")[0]
|
||||
assert "'all'" in map_section or '"all"' in map_section, (
|
||||
"FLYOUT_MENU_MAP must include an 'all' key"
|
||||
)
|
||||
assert "'user'" in map_section or '"user"' in map_section, (
|
||||
"FLYOUT_MENU_MAP must include a 'user' key"
|
||||
)
|
||||
assert "'hidden'" in map_section or '"hidden"' in map_section, (
|
||||
"FLYOUT_MENU_MAP must include a 'hidden' key"
|
||||
)
|
||||
|
||||
|
||||
def test_build_flyout_menu_items_function_exists() -> None:
|
||||
"""app.js must define a _buildFlyoutMenuItems function."""
|
||||
assert "function _buildFlyoutMenuItems" in _JS, (
|
||||
"app.js must contain a _buildFlyoutMenuItems function"
|
||||
)
|
||||
|
||||
|
||||
def test_build_flyout_uses_menu_map() -> None:
|
||||
"""_buildFlyoutMenuItems must reference FLYOUT_MENU_MAP."""
|
||||
fn_body = _JS.split("function _buildFlyoutMenuItems")[1].split("\nfunction ")[0]
|
||||
assert "FLYOUT_MENU_MAP" in fn_body, (
|
||||
"_buildFlyoutMenuItems must reference FLYOUT_MENU_MAP (data-driven, not if/else)"
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user