mirror of
https://github.com/pewdiepie-archdaemon/odysseus.git
synced 2026-09-25 01:22:19 +02:00
Squash Odysseus development history
This commit is contained in:
@@ -0,0 +1,201 @@
|
||||
import json
|
||||
import subprocess
|
||||
import textwrap
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
GEOMETRY_MODULE = (ROOT / "static/js/editor/layer-geometry.js").as_uri()
|
||||
MOVE_MODULE = (ROOT / "static/js/editor/tools/move.js").as_uri()
|
||||
STATE_MODULE = (ROOT / "static/js/editor/state.js").as_uri()
|
||||
|
||||
|
||||
def run_node(body: str):
|
||||
script = textwrap.dedent(
|
||||
f"""
|
||||
import {{
|
||||
createLayerGeometryController, normalizeLayerCoordinate,
|
||||
readLayerGeometry, setLayerPosition,
|
||||
}} from {json.dumps(GEOMETRY_MODULE)};
|
||||
import {{ createMoveTool }} from {json.dumps(MOVE_MODULE)};
|
||||
import {{ state }} from {json.dumps(STATE_MODULE)};
|
||||
globalThis.document = {{activeElement:null}};
|
||||
{body}
|
||||
"""
|
||||
)
|
||||
result = subprocess.run(
|
||||
["node", "--input-type=module", "-e", script],
|
||||
cwd=ROOT,
|
||||
text=True,
|
||||
capture_output=True,
|
||||
check=True,
|
||||
)
|
||||
return json.loads(result.stdout)
|
||||
|
||||
|
||||
def test_geometry_normalizes_coordinates_and_reports_layer_bounds():
|
||||
result = run_node(
|
||||
"""
|
||||
const layer = {id:'photo',canvas:{width:640,height:480}};
|
||||
const editor = {layerOffsets:new Map([['photo',{x:12.6,y:-7.4}]])};
|
||||
const geometry = readLayerGeometry(editor,layer);
|
||||
const moved = setLayerPosition(editor,layer,'42.8','bad');
|
||||
console.log(JSON.stringify({
|
||||
geometry,moved,
|
||||
high:normalizeLayerCoordinate(99999999),
|
||||
low:normalizeLayerCoordinate(-99999999),
|
||||
}));
|
||||
"""
|
||||
)
|
||||
assert result == {
|
||||
"geometry": {"x": 13, "y": -7, "width": 640, "height": 480},
|
||||
"moved": {"x": 43, "y": -7},
|
||||
"high": 1000000,
|
||||
"low": -1000000,
|
||||
}
|
||||
|
||||
|
||||
def test_nudges_coalesce_history_and_transform_position_tracks_without_extra_snapshot():
|
||||
result = run_node(
|
||||
"""
|
||||
const layer = {id:'photo',name:'Photo',canvas:{width:100,height:80},locked:false};
|
||||
Object.assign(state,{
|
||||
layers:[layer],activeLayerId:layer.id,
|
||||
layerOffsets:new Map([[layer.id,{x:0,y:0}]]),
|
||||
transformActive:false,transformLayer:null,transformOrigOffset:null,
|
||||
});
|
||||
const labels=[];
|
||||
const controller=createLayerGeometryController({
|
||||
activeLayer:()=>layer,saveState:label=>labels.push(label),composite:()=>{},
|
||||
});
|
||||
controller.nudge(1,0);
|
||||
controller.nudge(1,0);
|
||||
controller.endNudge();
|
||||
controller.nudge(0,10);
|
||||
controller.endNudge();
|
||||
state.transformActive=true;
|
||||
state.transformLayer=layer;
|
||||
state.transformOrigOffset={x:2,y:10};
|
||||
controller.nudge(5,-3);
|
||||
console.log(JSON.stringify({
|
||||
labels,offset:state.layerOffsets.get(layer.id),orig:state.transformOrigOffset,
|
||||
}));
|
||||
"""
|
||||
)
|
||||
assert result == {
|
||||
"labels": ['Nudge "Photo"', 'Nudge "Photo"'],
|
||||
"offset": {"x": 7, "y": 7},
|
||||
"orig": {"x": 7, "y": 7},
|
||||
}
|
||||
|
||||
|
||||
def test_move_drag_can_return_to_origin_and_transform_move_reuses_session_history():
|
||||
result = run_node(
|
||||
"""
|
||||
const layer={id:'photo',name:'Photo',canvas:{width:50,height:40},visible:true};
|
||||
const canvas={width:200,height:200,getBoundingClientRect:()=>({left:0,top:0,width:200,height:200})};
|
||||
Object.assign(state,{
|
||||
mainCanvas:canvas,imgWidth:200,imgHeight:200,zoom:1,
|
||||
layers:[layer],activeLayerId:layer.id,layerOffsets:new Map([[layer.id,{x:0,y:0}]]),
|
||||
moving:false,transformActive:false,
|
||||
});
|
||||
const labels=[];
|
||||
const positions=[];
|
||||
const tool=createMoveTool({
|
||||
activeLayer:()=>layer,saveState:label=>labels.push(label),composite:()=>{},
|
||||
onPositionChange:(_layer,_before,next)=>positions.push(next),
|
||||
});
|
||||
const event=(x,y)=>({clientX:x,clientY:y,preventDefault(){},ctrlKey:false,metaKey:false});
|
||||
tool.begin(event(10,10));
|
||||
tool.drag(event(20,10));
|
||||
tool.drag(event(10,10));
|
||||
tool.end();
|
||||
state.transformActive=true;
|
||||
tool.begin(event(10,10));
|
||||
tool.drag(event(15,10));
|
||||
tool.end();
|
||||
console.log(JSON.stringify({labels,positions,offset:state.layerOffsets.get(layer.id)}));
|
||||
"""
|
||||
)
|
||||
assert result["labels"] == ['Move "Photo"']
|
||||
assert result["positions"][:2] == [{"x": 10, "y": 0}, {"x": 0, "y": 0}]
|
||||
assert result["offset"] == {"x": 5, "y": 0}
|
||||
|
||||
|
||||
def test_position_lock_blocks_drag_and_nudge_without_blocking_other_layer_locks():
|
||||
result = run_node(
|
||||
"""
|
||||
const layer={id:'photo',name:'Photo',canvas:{width:50,height:40},visible:true,locks:{position:true}};
|
||||
const canvas={width:200,height:200,getBoundingClientRect:()=>({left:0,top:0,width:200,height:200})};
|
||||
Object.assign(state,{
|
||||
mainCanvas:canvas,imgWidth:200,imgHeight:200,zoom:1,
|
||||
layers:[layer],layerGroups:[],selectedLayerIds:[layer.id],activeLayerId:layer.id,
|
||||
layerOffsets:new Map([[layer.id,{x:0,y:0}]]),moving:false,transformActive:false,
|
||||
});
|
||||
const labels=[];
|
||||
const controller=createLayerGeometryController({activeLayer:()=>layer,saveState:label=>labels.push(label),composite:()=>{}});
|
||||
const tool=createMoveTool({activeLayer:()=>layer,saveState:label=>labels.push(label),composite:()=>{}});
|
||||
const event=(x,y)=>({clientX:x,clientY:y,preventDefault(){},ctrlKey:false,metaKey:false});
|
||||
controller.nudge(5,0);
|
||||
tool.begin(event(10,10));
|
||||
tool.drag(event(30,30));
|
||||
tool.end();
|
||||
const blocked={offset:state.layerOffsets.get(layer.id),labels:[...labels]};
|
||||
layer.locks={pixels:true,transparency:true,position:false};
|
||||
controller.nudge(5,0);
|
||||
console.log(JSON.stringify({blocked,allowed:state.layerOffsets.get(layer.id),labels}));
|
||||
"""
|
||||
)
|
||||
assert result["blocked"] == {"offset": {"x": 0, "y": 0}, "labels": []}
|
||||
assert result["allowed"] == {"x": 5, "y": 0}
|
||||
assert result["labels"] == ['Nudge "Photo"']
|
||||
|
||||
|
||||
def test_unlinked_mask_moves_independently_and_stays_fixed_when_parent_moves():
|
||||
result = run_node(
|
||||
"""
|
||||
const mask={id:'mask',name:'Layer Mask',mode:'layer',linked:false,offset:{x:4,y:6}};
|
||||
const layer={id:'photo',name:'Photo',canvas:{width:50,height:40},visible:true,masks:[mask],activeMaskId:mask.id};
|
||||
const canvas={width:200,height:200,getBoundingClientRect:()=>({left:0,top:0,width:200,height:200})};
|
||||
Object.assign(state,{
|
||||
mainCanvas:canvas,imgWidth:200,imgHeight:200,zoom:1,
|
||||
layers:[layer],layerGroups:[],selectedLayerIds:[layer.id],activeLayerId:layer.id,
|
||||
layerOffsets:new Map([[layer.id,{x:20,y:30}]]),moving:false,transformActive:false,
|
||||
snapEnabled:false,snapToGrid:false,guides:{vertical:[],horizontal:[]},
|
||||
});
|
||||
const labels=[];
|
||||
const tool=createMoveTool({activeLayer:()=>layer,saveState:label=>labels.push(label),composite:()=>{}});
|
||||
const event=(x,y)=>({clientX:x,clientY:y,preventDefault(){},ctrlKey:false,metaKey:false});
|
||||
tool.begin(event(10,10));
|
||||
tool.drag(event(17,14));
|
||||
tool.end();
|
||||
const independent={layer:state.layerOffsets.get(layer.id),mask:{...mask.offset}};
|
||||
layer.activeMaskId=null;
|
||||
tool.begin(event(10,10));
|
||||
tool.drag(event(22,15));
|
||||
tool.end();
|
||||
console.log(JSON.stringify({labels,independent,layer:state.layerOffsets.get(layer.id),mask:mask.offset,
|
||||
documentMask:{x:state.layerOffsets.get(layer.id).x+mask.offset.x,y:state.layerOffsets.get(layer.id).y+mask.offset.y}}));
|
||||
"""
|
||||
)
|
||||
assert result == {
|
||||
"labels": ['Move mask "Layer Mask"', 'Move "Photo"'],
|
||||
"independent": {"layer": {"x": 20, "y": 30}, "mask": {"x": 11, "y": 10}},
|
||||
"layer": {"x": 32, "y": 35},
|
||||
"mask": {"x": -1, "y": 5},
|
||||
"documentMask": {"x": 31, "y": 40},
|
||||
}
|
||||
|
||||
|
||||
def test_geometry_controls_and_arrow_nudging_are_wired_offline():
|
||||
controls = (ROOT / "static/js/editor/build/controls.js").read_text(encoding="utf-8")
|
||||
keyboard = (ROOT / "static/js/editor/keyboard-shortcuts.js").read_text(encoding="utf-8")
|
||||
editor = (ROOT / "static/js/galleryEditor.js").read_text(encoding="utf-8")
|
||||
service_worker = (ROOT / "static/sw.js").read_text(encoding="utf-8")
|
||||
|
||||
for field_id in ("ge-layer-x", "ge-layer-y", "ge-layer-width", "ge-layer-height"):
|
||||
assert f'id="{field_id}"' in controls
|
||||
assert "e.key.startsWith('Arrow')" in keyboard
|
||||
assert "nudgeActiveLayer?.(...delta)" in keyboard
|
||||
assert "_layerGeometry.trackExternalMove" in editor
|
||||
assert "/static/js/editor/layer-geometry.js" in service_worker
|
||||
Reference in New Issue
Block a user