diff --git a/vasl_templates/webapp/data/default-template-pack/turn_track.j2 b/vasl_templates/webapp/data/default-template-pack/turn_track.j2 index 50e72d7..99f07be 100644 --- a/vasl_templates/webapp/data/default-template-pack/turn_track.j2 +++ b/vasl_templates/webapp/data/default-template-pack/turn_track.j2 @@ -22,14 +22,15 @@ td.no-reinforce { {{RESET_TD}} ; width: 13px ; } td.reinforce1 { {{RESET_TD}} ; width: 13px ; background: url("{{TURN_TRACK_FLAG_1}}") top left no-repeat ; vertical-align: top ; } td.reinforce2 { {{RESET_TD}} ; width: 13px ; background: url("{{TURN_TRACK_FLAG_2}}") bottom right no-repeat ; vertical-align: bottom ; } td.half-turn { - background: url("{{IMAGES_BASE_URL}}/turn-track-half-turn.png") bottom right no-repeat ; + background: url("{{TURN_TRACK_HALF_TURN_IMAGE_URL}}") bottom right no-repeat ; background-size: contain ; {# nb: doesn't work in VASSAL, the image file needs to be the correct size :-/ #} } {% if TURN_TRACK_PREVIEW_MODE %} body { margin: 0 ; } .reinforce1, .reinforce2 { opacity: 0 ; } -.click { width: 13px ; height: 13px ; cursor: pointer ; } +.flag-click { width: 13px ; height: 13px ; cursor: pointer ; } +.shading-click { cursor: pointer ; } {%endif%} @@ -45,6 +46,12 @@ function onFlagClick( turnNo, playerNo ) { turnNo: turnNo, uiPlayerNo: playerNo }, "*" ) ; } +function onShadingClick( turnNo ) { + window.parent.postMessage( { + type: "ShadingClick", + turnNo: turnNo + }, "*" ) ; +} {%endif%} @@ -54,27 +61,40 @@ function onFlagClick( turnNo, playerNo ) { {% for turnSquare in row %} - + - +
{% if TURN_TRACK_PREVIEW_MODE %} -
{%endif%}
{{turnSquare[0]}} +{% if TURN_TRACK_PREVIEW_MODE %} +
+ {{turnSquare[0]}} +
+{%else%} + {{turnSquare[0]}} +{%endif%} +
{% if TURN_TRACK_PREVIEW_MODE and turnSquare[0] != TURN_TRACK_HALF_TURN %} -
{%endif%} diff --git a/vasl_templates/webapp/static/snippets.js b/vasl_templates/webapp/static/snippets.js index 642a1a6..8e563fd 100644 --- a/vasl_templates/webapp/static/snippets.js +++ b/vasl_templates/webapp/static/snippets.js @@ -530,23 +530,31 @@ function make_turn_track_params( params ) turnNo = 1 + row * args.width + col ; if ( turnNo > args.nTurns ) break ; - var val = [ turnNo, args.reinforce2[turnNo]?true:false, args.reinforce1[turnNo]?true:false ] ; + var val = [ turnNo, + args.shading[turnNo] ? true : false, + args.reinforce2[turnNo] ? true : false, + args.reinforce1[turnNo] ? true : false, + ] ; if ( params.TURN_TRACK.SWAP_PLAYERS ) - val = [ val[0], val[2], val[1] ] ; + val = [ val[0], val[1], val[3], val[2] ] ; turnTrackSquares[ turnTrackSquares.length-1 ].push( val ) ; nTurnTrackSquares += 1 ; } } // update the snippet params + var forceLocalImages = params.TURN_TRACK_PREVIEW_MODE ; params.TURN_TRACK_SQUARES = turnTrackSquares ; if ( args.halfTurn ) params.TURN_TRACK_HALF_TURN = nTurnTrackSquares ; + params.TURN_TRACK_HALF_TURN_IMAGE_URL = forceLocalImages ? + make_app_url( "/static/images/turn-track-half-turn.png", true ) : + params.IMAGES_BASE_URL + "/turn-track-half-turn.png" ; + params.TURN_TRACK_SHADING_COLOR = TURN_TRACK_SHADING_COLOR ; // NOTE: The convention is that player 1 sets up first, player 2 moves first, // so swapping players actually maps turn track player 1 to the real player 1. // NOTE: We generate the player flag URL's instead of using params.PLAYER_FLAG_1/2 // so that flags will work even if the user has disabled player flags in snippets. - var forceLocalImages = params.TURN_TRACK_PREVIEW_MODE ; params.TURN_TRACK_FLAG_1 = make_player_flag_url( get_player_nat( params.TURN_TRACK.SWAP_PLAYERS ? 1 : 2 ), true, forceLocalImages @@ -559,7 +567,7 @@ function make_turn_track_params( params ) function parseTurnTrackParams( params ) { - function parseReinforcements( reinf ) { + function parseCommaList( reinf ) { var turnFlags = {} ; reinf.split( "," ).forEach( function( turnNo ) { turnNo = parseInt( turnNo.trim() ) ; @@ -580,12 +588,13 @@ function parseTurnTrackParams( params ) var width = params.TURN_TRACK.WIDTH ; if ( width === "" ) width = vertical ? 1 : nTurns ; - var reinforce1 = parseReinforcements( params.TURN_TRACK.REINFORCEMENTS_1 ) ; - var reinforce2 = parseReinforcements( params.TURN_TRACK.REINFORCEMENTS_2 ) ; + var shading = parseCommaList( params.TURN_TRACK.SHADING ) ; + var reinforce1 = parseCommaList( params.TURN_TRACK.REINFORCEMENTS_1 ) ; + var reinforce2 = parseCommaList( params.TURN_TRACK.REINFORCEMENTS_2 ) ; return { nTurns: nTurns, halfTurn: halfTurn, - vertical: vertical, width: width, + vertical: vertical, width: width, shading: shading, reinforce1: reinforce1, reinforce2: reinforce2 } ; } @@ -959,6 +968,7 @@ function unload_snippet_params( unpack_scenario_date, template_id ) "NTURNS": nTurns, "WIDTH": isNaN( parseInt( width ) ) ? "" : width, "VERTICAL": $( "input[name='TURN_TRACK_VERTICAL']" ).prop( "checked" ), + "SHADING": $( "input[name='TURN_TRACK_SHADING']" ).val().trim(), "REINFORCEMENTS_1": $( "input[name='TURN_TRACK_REINFORCEMENTS_1']" ).val().trim(), "REINFORCEMENTS_2": $( "input[name='TURN_TRACK_REINFORCEMENTS_2']" ).val().trim(), "SWAP_PLAYERS": $( "input[name='TURN_TRACK_SWAP_PLAYERS']" ).prop( "checked" ), @@ -1756,6 +1766,7 @@ function do_load_scenario_data( params ) setTurnTrackNTurns( params[key].NTURNS ) ; $( "input[name='TURN_TRACK_VERTICAL']" ).prop( "checked", params[key].VERTICAL ) ; $( "input[name='TURN_TRACK_WIDTH']" ).val( params[key].WIDTH ) ; + $( "input[name='TURN_TRACK_SHADING']" ).val( params[key].SHADING ) ; $( "input[name='TURN_TRACK_REINFORCEMENTS_1']" ).val( params[key].REINFORCEMENTS_1 ) ; $( "input[name='TURN_TRACK_REINFORCEMENTS_2']" ).val( params[key].REINFORCEMENTS_2 ) ; $( "input[name='TURN_TRACK_SWAP_PLAYERS']" ).prop( "checked", params[key].SWAP_PLAYERS ) ; diff --git a/vasl_templates/webapp/static/turn_track.js b/vasl_templates/webapp/static/turn_track.js index 59e97a7..801b79f 100644 --- a/vasl_templates/webapp/static/turn_track.js +++ b/vasl_templates/webapp/static/turn_track.js @@ -1,10 +1,12 @@ DEFAULT_TURN_TRACK_TURNS_MIN = 6 ; DEFAULT_TURN_TRACK_TURNS_MAX = 10 ; +TURN_TRACK_SHADING_COLOR = "#e0e0e0" ; // NOTE: Reinforcement flags get clipped on turn 100, but this is unlikely to be an issue :-/ _MAX_TURN_TRACK_TURNS = 100 ; gTurnTrackReinforcements = null ; +gTurnTrackShading = null ; // -------------------------------------------------------------------- @@ -14,6 +16,7 @@ function editTurnTrackSettings() var $dlg, $iframe, iframeSeqNo=0 ; // FUDGE! This should work as a local variable, but causes a weird problem where it doesn't get reset properly :-/ gTurnTrackReinforcements = null ; + gTurnTrackShading = null ; function loadControls() { // load the dialog controls @@ -34,6 +37,7 @@ function editTurnTrackSettings() var params = updatePreview( false ) ; var args = parseTurnTrackParams( params ) ; gTurnTrackReinforcements = { 1: args.reinforce1, 2: args.reinforce2 } ; + gTurnTrackShading = args.shading ; // update the UI updateUI() ; } @@ -46,9 +50,11 @@ function editTurnTrackSettings() $panel.find( "input[name='TURN_TRACK_WIDTH']" ).val( "" ) ; $panel.find( "input[name='TURN_TRACK_VERTICAL']" ).prop( "checked", false ) ; $panel.find( "input[name='TURN_TRACK_SWAP_PLAYERS']" ).prop( "checked", false ) ; + $panel.find( "input[name='TURN_TRACK_SHADING']" ).val( "" ) ; $panel.find( "input[name='TURN_TRACK_REINFORCEMENTS_1']" ).val( "" ) ; $panel.find( "input[name='TURN_TRACK_REINFORCEMENTS_2']" ).val( "" ) ; gTurnTrackReinforcements = null ; + gTurnTrackShading = null ; loadControls() ; } } ) ; @@ -141,6 +147,21 @@ function editTurnTrackSettings() updateFlag( turnNo, playerNo ) ; } + function onShadingClick( turnNo ) { + // NOTE: This method gets called by a click handler in the snippet HTML. + // toggle the turn track square's shading + if ( gTurnTrackShading[turnNo] ) + delete gTurnTrackShading[turnNo] ; + else + gTurnTrackShading[turnNo] = true ; + $panel.find( "input[name='TURN_TRACK_SHADING']" ).val( + Object.keys( gTurnTrackShading ).join( "," ) + ) ; + $iframe.contents().find( "#turn-square-" + turnNo ).css( { + "background-color": gTurnTrackShading && gTurnTrackShading[turnNo] ? TURN_TRACK_SHADING_COLOR : "inherit" + } ) ; + } + function updateFlag( turnNo, playerNo ) { // update the specified reinforcement flag $iframe.contents().find( "#flag-" + turnNo + "_" + flipPlayerNo2(playerNo) ).css( { @@ -225,6 +246,8 @@ function editTurnTrackSettings() window.addEventListener( "message", function( evt ) { if ( evt.data.type === "FlagClick" ) onFlagClick( evt.data.turnNo, flipPlayerNo2(evt.data.uiPlayerNo) ) ; + else if ( evt.data.type === "ShadingClick" ) + onShadingClick( evt.data.turnNo ) ; } ) ; }, diff --git a/vasl_templates/webapp/templates/tabs-scenario.html b/vasl_templates/webapp/templates/tabs-scenario.html index e0c276d..e586e8f 100644 --- a/vasl_templates/webapp/templates/tabs-scenario.html +++ b/vasl_templates/webapp/templates/tabs-scenario.html @@ -35,9 +35,10 @@
diff --git a/vasl_templates/webapp/tests/test_turn_track.py b/vasl_templates/webapp/tests/test_turn_track.py index 6513dea..8eb481d 100644 --- a/vasl_templates/webapp/tests/test_turn_track.py +++ b/vasl_templates/webapp/tests/test_turn_track.py @@ -44,10 +44,10 @@ def test_turn_track_controls( webapp, webdriver ): # show the turn track dialog dlg = _show_turn_track_dialog( 6 ) with SwitchFrame( webdriver, "#turn-track-preview" ): - _click_reinf_flag( 1, 1 ) - _click_reinf_flag( 2, 1 ) - _click_reinf_flag( 2, 2 ) - _click_reinf_flag( 3, 2 ) + _toggle_reinf( 1, 1 ) + _toggle_reinf( 2, 1 ) + _toggle_reinf( 2, 2 ) + _toggle_reinf( 3, 2 ) # change the width _change_turn_track_width( dlg, 3 ) @@ -100,10 +100,10 @@ def test_turn_track_reinforcements( webapp, webdriver ): # turn on some reinforcements, then check the snippet with SwitchFrame( webdriver, "#turn-track-preview" ): - _click_reinf_flag( 2, 1 ) - _click_reinf_flag( 3, 1 ) - _click_reinf_flag( 3, 2 ) - _click_reinf_flag( 7, 1 ) + _toggle_reinf( 2, 1 ) + _toggle_reinf( 3, 1 ) + _toggle_reinf( 3, 2 ) + _toggle_reinf( 7, 1 ) assert _generate_turn_track_snippet( dlg ) == [ [ (1,None,None), (2,"player1",None), (3,"player1","player2"), (4,None,None), (5,None,None) , (6,None,None), (7,"player1",None) @@ -112,11 +112,11 @@ def test_turn_track_reinforcements( webapp, webdriver ): # turn off some reinforcements, turn some on, then check the snippet with SwitchFrame( webdriver, "#turn-track-preview" ): - _click_reinf_flag( 2, 2 ) - _click_reinf_flag( 3, 1 ) - _click_reinf_flag( 3, 2 ) - _click_reinf_flag( 5, 2 ) - _click_reinf_flag( 7, 1 ) + _toggle_reinf( 2, 2 ) + _toggle_reinf( 3, 1 ) + _toggle_reinf( 3, 2 ) + _toggle_reinf( 5, 2 ) + _toggle_reinf( 7, 1 ) assert _generate_turn_track_snippet( dlg ) == [ [ (1,None,None), (2,"player1","player2"), (3,None,None), (4,None,None), (5,None,"player2") , (6,None,None), (7,None,None) @@ -125,6 +125,40 @@ def test_turn_track_reinforcements( webapp, webdriver ): # --------------------------------------------------------------------- +def test_turn_track_shading( webapp, webdriver ): + """Test shading squares on the turn track.""" + + # initialize + webapp.control_tests.set_data_dir( "{REAL}" ) + init_webapp( webapp, webdriver ) + + # show the turn track dialog + dlg = _show_turn_track_dialog( 6.5 ) + + # shade some turn track squares, then check the snippet + with SwitchFrame( webdriver, "#turn-track-preview" ): + _toggle_shading( 1 ) + _toggle_shading( 2 ) + _toggle_shading( 7 ) + assert _generate_turn_track_snippet( dlg ) == [ + [ (1,None,None,True), (2,None,None,True), (3,None,None), + (4,None,None), (5,None,None) , (6,None,None), (7,None,None,True) + ] + ] + + # change the shading for some turn track squares, then check the snippet + with SwitchFrame( webdriver, "#turn-track-preview" ): + _toggle_shading( 1 ) + _toggle_shading( 3 ) + _toggle_shading( 7 ) + assert _generate_turn_track_snippet( dlg ) == [ + [ (1,None,None), (2,None,None,True), (3,None,None,True), + (4,None,None), (5,None,None) , (6,None,None), (7,None,None) + ] + ] + +# --------------------------------------------------------------------- + def test_turn_track_persistence( webapp, webdriver ): """Test saving and loading turn track settings.""" @@ -141,10 +175,12 @@ def test_turn_track_persistence( webapp, webdriver ): # configure the turn track with SwitchFrame( webdriver, "#turn-track-preview" ): - _click_reinf_flag( 1, 1 ) - _click_reinf_flag( 2, 2 ) - _click_reinf_flag( 3, 1 ) - _click_reinf_flag( 3, 2 ) + _toggle_reinf( 1, 1 ) + _toggle_reinf( 2, 2 ) + _toggle_reinf( 3, 1 ) + _toggle_reinf( 3, 2 ) + _toggle_shading( 2 ) + _toggle_shading( 4 ) _change_turn_track_width( dlg, 4 ) _swap_turn_track_players( dlg ) _change_turn_track_direction( dlg ) @@ -152,7 +188,7 @@ def test_turn_track_persistence( webapp, webdriver ): # check the snippet expected = [ [ (1,None,"player2"), (3,"player1","player2"), (5,None,None), (7,None,None) ], - [ (2,"player1",None) , (4,None,None), (6,None,None) ] + [ (2,"player1",None,True) , (4,None,None,True), (6,None,None) ] ] wait_for( 2, lambda: _generate_turn_track_snippet( dlg ) == expected @@ -164,6 +200,7 @@ def test_turn_track_persistence( webapp, webdriver ): assert saved_scenario["TURN_TRACK"] == { "NTURNS": "6.5", "WIDTH": "4", "VERTICAL": True, "SWAP_PLAYERS": True, + "SHADING": "2,4", "REINFORCEMENTS_1": "2,3", "REINFORCEMENTS_2": "1,3", } assert _generate_turn_track_snippet( None ) == expected @@ -264,13 +301,18 @@ def _generate_turn_track_snippet( dlg ): return None def unload_square( square ): + # unload the reinforcement flags cells = square.xpath( ".//td" ) assert len(cells) == 3 - return ( + vals = ( int( cells[1].text ), get_reinforce_class( cells[0] ), get_reinforce_class( cells[2] ), ) + # check if the square is shaded + if any( s.startswith( "background-color:" ) for s in square.xpath( ".//@style" ) ): + vals = ( *vals, True ) + return vals # unload the snippet contents squares = unload_table( "//table[@class='turn-track']", html=clipboard, unload=False ) @@ -302,10 +344,16 @@ def _unload_turn_track_droplist(): keys.append( key ) return keys -def _click_reinf_flag( turn_no, player_no ): - """Click on a reinforcement flag.""" +def _toggle_reinf( turn_no, player_no ): + """Toggle a player's reinforcements for the specified turn.""" + find_child( + "#flag-{}_{} .flag-click".format( turn_no, player_no ) + ).click() + +def _toggle_shading( turn_no ): + """Toggle the shading for a turn track square.""" find_child( - "#flag-{}_{} .click".format( turn_no, player_no ) + "#turn-square-{} .shading-click".format( turn_no ) ).click() # ---------------------------------------------------------------------