mirror of
https://github.com/pewdiepie-archdaemon/odysseus.git
synced 2026-10-21 22:32:20 +02:00
feat(photo-editor): Ajax Image Editor client (Photoshop-parity tools)
Photoshop-parity editor client: layers, selection/masking, brushes,
smart filters, LUT import, Quick Edit, mobile gestures, workspaces,
batch operations, and the service-worker versioning (v978->v1006).
Source: vendor/photocraft (ad1cff44) photo-editor client files, merged
onto upstream/dev (a8c147b2). Conflict resolution documented in
pr_work/A_conflicts.md; editor files taken from vendor/photocraft
(upstream's editor is an earlier snapshot of the same feature).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
c74f475679
commit
5fac693c1c
@@ -0,0 +1,128 @@
|
||||
"""Static contract tests for the View > Panels visibility feature.
|
||||
|
||||
The panel-visibility module, its CSS, the View/Window menu markup, the wiring
|
||||
and the control-op catalog are plain JavaScript, so these tests assert the
|
||||
contract at the source level (the project's editor suites are contract/static,
|
||||
not a JS runtime).
|
||||
"""
|
||||
import re
|
||||
from pathlib import Path
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
|
||||
MODULE = ROOT / "static/js/editor/panel-visibility.js"
|
||||
CSS = ROOT / "static/css/13-image-editor.css"
|
||||
TOPBAR = ROOT / "static/js/editor/build/topbar.js"
|
||||
VIEW_WIRE = ROOT / "static/js/editor/wire-view-menu.js"
|
||||
EXTRA_WIRE = ROOT / "static/js/editor/wire-extra-menus.js"
|
||||
GALLERY = ROOT / "static/js/galleryEditor.js"
|
||||
SW = ROOT / "static/sw.js"
|
||||
|
||||
|
||||
def _read(path):
|
||||
return path.read_text(encoding="utf-8")
|
||||
|
||||
|
||||
def test_module_registry_and_api():
|
||||
src = _read(MODULE)
|
||||
assert "export const PANELS = Object.freeze([" in src
|
||||
for pid in ["swatches", "gradients", "patterns", "properties", "adjustments",
|
||||
"histogram", "info", "channels", "paths", "character",
|
||||
"navigator", "history", "actions", "layers", "options"]:
|
||||
assert f"id: '{pid}'" in src, pid
|
||||
for fn in ["export function isVisible(id)",
|
||||
"export function list()",
|
||||
"export function apply()",
|
||||
"export function setVisible(id, visible)",
|
||||
"export function toggle(id)",
|
||||
"export function showAll()",
|
||||
"export function hideAll()",
|
||||
"export function reset()",
|
||||
"export function subscribe(fn)"]:
|
||||
assert fn in src, fn
|
||||
|
||||
|
||||
def test_module_persists_and_tags_dom():
|
||||
src = _read(MODULE)
|
||||
assert "const STORAGE_KEY = 'ge-panel-visibility';" in src
|
||||
assert 'localStorage.setItem(STORAGE_KEY, JSON.stringify(map))' in src
|
||||
assert 'data-panel-hidden' in src
|
||||
# Tags the wrapper, the tab-strip item, the compact select option,
|
||||
# the collapsed group, the pinned Layers strip and the Tool Options bar.
|
||||
assert '.ge-dock-panel[data-panel="${id}"]' in src
|
||||
assert '.ge-dock-tab-item[data-panel="${id}"]' in src
|
||||
assert '.ge-dock-select option[value="${id}"]' in src
|
||||
assert '.ge-dock-group[data-group="${group}"]' in src
|
||||
assert "document.querySelector('.ge-layers')" in src
|
||||
assert "document.querySelector('.ge-controls')" in src
|
||||
|
||||
|
||||
def test_css_hides_tagged_nodes():
|
||||
src = _read(CSS)
|
||||
assert '.ge-dock-panel[data-panel-hidden="1"]' in src
|
||||
assert '.ge-dock-tab-item[data-panel-hidden="1"]' in src
|
||||
assert '.ge-dock-group[data-panel-hidden="1"]' in src
|
||||
assert '.ge-dock-divider[data-panel-hidden="1"]' in src
|
||||
assert '.ge-layers[data-panel-hidden="1"]' in src
|
||||
assert '.ge-controls[data-panel-hidden="1"]' in src
|
||||
|
||||
|
||||
def test_view_menu_has_panels_group_and_layout_actions():
|
||||
src = _read(TOPBAR)
|
||||
assert '<div class="ge-menu-label">Panels</div>' in src
|
||||
assert '<div class="ge-menu-label">Panel layout</div>' in src
|
||||
for pid in ["options", "layers", "swatches", "gradients", "patterns",
|
||||
"properties", "adjustments", "histogram", "info", "channels",
|
||||
"paths", "character", "navigator", "history", "actions"]:
|
||||
assert f'data-view-action="panel-{pid}"' in src, pid
|
||||
for action in ["panel-show-all", "panel-hide-all", "panel-reset"]:
|
||||
assert f'data-view-action="{action}"' in src, action
|
||||
|
||||
|
||||
def test_view_menu_wiring():
|
||||
src = _read(VIEW_WIRE)
|
||||
assert "import * as panelVisibility from './panel-visibility.js';" in src
|
||||
assert '[data-view-action="panel-${panel.id}"]' in src
|
||||
assert "item?.classList.toggle('active', !!panel.visible);" in src
|
||||
assert "if (action === 'panel-show-all')" in src
|
||||
assert "if (action === 'panel-hide-all')" in src
|
||||
assert "if (action === 'panel-reset')" in src
|
||||
assert "if (action.startsWith('panel-'))" in src
|
||||
assert "panelVisibility.toggle(action.slice('panel-'.length))" in src
|
||||
|
||||
|
||||
def test_window_menu_keeps_the_show_panel_contract():
|
||||
# The Window menu stays a "bring a panel to front / focus it" menu; panel
|
||||
# show/hide toggles live in the View menu (above). Guards against the two
|
||||
# menus claiming the same data-window-action values.
|
||||
src = _read(TOPBAR)
|
||||
for action in ["options", "layers", "properties", "character", "adjustments",
|
||||
"swatches", "gradients", "channels", "paths", "patterns",
|
||||
"histogram", "info", "navigator", "history", "actions"]:
|
||||
assert f'data-window-action="{action}"' in src, action
|
||||
assert 'data-window-action="panel-' not in src
|
||||
|
||||
|
||||
def test_window_menu_wiring_targets_existing_surfaces():
|
||||
src = _read(EXTRA_WIRE)
|
||||
assert "togglePanel?.(action)" in src
|
||||
assert "click('ge-history-btn')" in src
|
||||
assert 'data-window-action="panel-' not in src
|
||||
assert "panelVisibility" not in src
|
||||
|
||||
|
||||
def test_gallery_editor_mounts_and_exposes_control_ops():
|
||||
src = _read(GALLERY)
|
||||
assert "import * as panelVisibility from './editor/panel-visibility.js';" in src
|
||||
assert "panelVisibility.apply();" in src
|
||||
assert "window.gePanelVisibility = panelVisibility;" in src
|
||||
for op in ["panels.list", "panels.setVisible", "panels.toggle",
|
||||
"panels.showAll", "panels.hideAll", "panels.reset"]:
|
||||
assert f"'{op}':" in src, op
|
||||
assert "panelVisibility.setVisible(p.id, p.visible !== false)" in src
|
||||
assert "panelVisibility.toggle(p.id)" in src
|
||||
|
||||
|
||||
def test_sw_cache_name_bumped():
|
||||
src = _read(SW)
|
||||
assert re.search(r"odysseus-v\d+-pr40-editor-precache", src)
|
||||
Reference in New Issue
Block a user