Allow multiple levels of shading in the turn track.

master
Pacman Ghost 2 years ago
parent 729c6e306d
commit d165bfdefd
  1. 9
      vasl_templates/webapp/data/default-template-pack/turn_track.j2
  2. 3
      vasl_templates/webapp/main.py
  3. 33
      vasl_templates/webapp/static/snippets.js
  4. 58
      vasl_templates/webapp/static/turn_track.js
  5. 46
      vasl_templates/webapp/tests/test_turn_track.py

@ -28,6 +28,9 @@ td.half-turn {
{% if TURN_TRACK_PREVIEW_MODE %} {% if TURN_TRACK_PREVIEW_MODE %}
body { margin: 0 ; } body { margin: 0 ; }
body ::selection {}
body ::moz-selection {}
body { user-select: none ; }
.reinforce1, .reinforce2 { opacity: 0 ; } .reinforce1, .reinforce2 { opacity: 0 ; }
.flag-click { width: 13px ; height: 13px ; cursor: pointer ; } .flag-click { width: 13px ; height: 13px ; cursor: pointer ; }
.shading-click { cursor: pointer ; } .shading-click { cursor: pointer ; }
@ -63,13 +66,13 @@ function onShadingClick( turnNo ) {
{% for turnSquare in row %} {% for turnSquare in row %}
<td id="turn-square-{{turnSquare[0]}}" <td id="turn-square-{{turnSquare[0]}}"
{%if turnSquare[0] == TURN_TRACK_HALF_TURN%} class="half-turn" {%endif%} {%if turnSquare[0] == TURN_TRACK_HALF_TURN%} class="half-turn" {%endif%}
{% if turnSquare[1] %} style="background-color:{{TURN_TRACK_SHADING_COLOR}};" {%endif%} {% if turnSquare[3] %} style="background-color:{{turnSquare[3]}};" {%endif%}
> >
<table style="width:100%;height:100%;"> <tr> <table style="width:100%;height:100%;"> <tr>
<td id="flag-{{turnSquare[0]}}_1" width="100%" <td id="flag-{{turnSquare[0]}}_1" width="100%"
class = {% if turnSquare[2] %} "reinforce1" {%else%} "no-reinforce" {%endif%} class = {% if turnSquare[1] %} "reinforce1" {%else%} "no-reinforce" {%endif%}
> >
{% if TURN_TRACK_PREVIEW_MODE %} {% if TURN_TRACK_PREVIEW_MODE %}
<div class="flag-click" <div class="flag-click"
@ -91,7 +94,7 @@ function onShadingClick( turnNo ) {
</td> </td>
<td id="flag-{{turnSquare[0]}}_2" width="100%" <td id="flag-{{turnSquare[0]}}_2" width="100%"
class = {% if turnSquare[3] and turnSquare[0] != TURN_TRACK_HALF_TURN %} "reinforce2" {%else%} "no-reinforce" {%endif%} class = {% if turnSquare[2] and turnSquare[0] != TURN_TRACK_HALF_TURN %} "reinforce2" {%else%} "no-reinforce" {%endif%}
> >
{% if TURN_TRACK_PREVIEW_MODE and turnSquare[0] != TURN_TRACK_HALF_TURN %} {% if TURN_TRACK_PREVIEW_MODE and turnSquare[0] != TURN_TRACK_HALF_TURN %}
<div class="flag-click" <div class="flag-click"

@ -75,6 +75,7 @@ _APP_CONFIG_DEFAULTS = { # Bodhgaya, India (APR/19)
"ONLINE_COUNTER_IMAGES_URL_TEMPLATE": "https://raw.githubusercontent.com/vasl-developers/vasl/develop/dist/images/{{PATH}}", #pylint: disable=line-too-long "ONLINE_COUNTER_IMAGES_URL_TEMPLATE": "https://raw.githubusercontent.com/vasl-developers/vasl/develop/dist/images/{{PATH}}", #pylint: disable=line-too-long
"ONLINE_EXTN_COUNTER_IMAGES_URL_TEMPLATE": "http://vasl-templates.org/services/counter/{{EXTN_ID}}/{{PATH}}", "ONLINE_EXTN_COUNTER_IMAGES_URL_TEMPLATE": "http://vasl-templates.org/services/counter/{{EXTN_ID}}/{{PATH}}",
"ASA_UPLOAD_URL": "https://aslscenarioarchive.com/rest/update/{ID}?user={USER}&token={TOKEN}", "ASA_UPLOAD_URL": "https://aslscenarioarchive.com/rest/update/{ID}?user={USER}&token={TOKEN}",
"TURN_TRACK_SHADING_COLORS": [ "#e0e0e0", "#c0c0c0" ],
} }
@app.route( "/app-config" ) @app.route( "/app-config" )
@ -99,6 +100,8 @@ def get_app_config():
} }
if isinstance( vals["THEATERS"], str ): if isinstance( vals["THEATERS"], str ):
vals["THEATERS"] = vals["THEATERS"].split() vals["THEATERS"] = vals["THEATERS"].split()
if isinstance( vals["TURN_TRACK_SHADING_COLORS"], str ):
vals["TURN_TRACK_SHADING_COLORS"] = vals["TURN_TRACK_SHADING_COLORS"].split()
for key in [ "APP_NAME", "APP_VERSION", "APP_DESCRIPTION", "APP_HOME_URL" ]: for key in [ "APP_NAME", "APP_VERSION", "APP_DESCRIPTION", "APP_HOME_URL" ]:
vals[ key ] = getattr( vasl_templates.webapp.config.constants, key ) vals[ key ] = getattr( vasl_templates.webapp.config.constants, key )

@ -519,6 +519,7 @@ function make_turn_track_params( params )
// generate the data for each turn track square // generate the data for each turn track square
var turnTrackSquares=[], nTurnTrackSquares=0 ; var turnTrackSquares=[], nTurnTrackSquares=0 ;
var shadings = parseTurnTrackShadings( args.shadings ) ;
var nRows = Math.ceil( args.nTurns / args.width ) ; var nRows = Math.ceil( args.nTurns / args.width ) ;
for ( var row=0 ; row < nRows ; ++row ) { for ( var row=0 ; row < nRows ; ++row ) {
turnTrackSquares.push( [] ) ; turnTrackSquares.push( [] ) ;
@ -530,14 +531,15 @@ function make_turn_track_params( params )
turnNo = 1 + row * args.width + col ; turnNo = 1 + row * args.width + col ;
if ( turnNo > args.nTurns ) if ( turnNo > args.nTurns )
break ; break ;
var val = [ turnNo, var vals = [ turnNo,
args.shading[turnNo] ? true : false,
args.reinforce2[turnNo] ? true : false, args.reinforce2[turnNo] ? true : false,
args.reinforce1[turnNo] ? true : false, args.reinforce1[turnNo] ? true : false,
] ; ] ;
if ( params.TURN_TRACK.SWAP_PLAYERS ) if ( params.TURN_TRACK.SWAP_PLAYERS )
val = [ val[0], val[1], val[3], val[2] ] ; vals = [ vals[0], vals[2], vals[1] ] ;
turnTrackSquares[ turnTrackSquares.length-1 ].push( val ) ; if ( shadings[turnNo] )
vals.push( gAppConfig.TURN_TRACK_SHADING_COLORS[ shadings[turnNo] - 1 ] ) ;
turnTrackSquares[ turnTrackSquares.length-1 ].push( vals ) ;
nTurnTrackSquares += 1 ; nTurnTrackSquares += 1 ;
} }
} }
@ -550,7 +552,6 @@ function make_turn_track_params( params )
params.TURN_TRACK_HALF_TURN_IMAGE_URL = forceLocalImages ? params.TURN_TRACK_HALF_TURN_IMAGE_URL = forceLocalImages ?
make_app_url( "/static/images/turn-track-half-turn.png", true ) : make_app_url( "/static/images/turn-track-half-turn.png", true ) :
params.IMAGES_BASE_URL + "/turn-track-half-turn.png" ; 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, // 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. // 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 // NOTE: We generate the player flag URL's instead of using params.PLAYER_FLAG_1/2
@ -567,12 +568,16 @@ function make_turn_track_params( params )
function parseTurnTrackParams( params ) function parseTurnTrackParams( params )
{ {
function parseCommaList( reinf ) { function parseCommaList( reinf, verbatim ) {
var turnFlags = {} ; var turnFlags = verbatim ? [] : {} ;
reinf.split( "," ).forEach( function( turnNo ) { reinf.split( "," ).forEach( function( turnNo ) {
turnNo = parseInt( turnNo.trim() ) ; if ( verbatim )
if ( ! isNaN( turnNo ) ) turnFlags.push( turnNo.trim() ) ;
turnFlags[ turnNo ] = true ; else {
turnNo = parseInt( turnNo.trim() ) ;
if ( ! isNaN( turnNo ) )
turnFlags[ turnNo ] = true ;
}
} ) ; } ) ;
return turnFlags ; return turnFlags ;
} }
@ -588,13 +593,13 @@ function parseTurnTrackParams( params )
var width = params.TURN_TRACK.WIDTH ; var width = params.TURN_TRACK.WIDTH ;
if ( width === "" ) if ( width === "" )
width = vertical ? 1 : nTurns ; width = vertical ? 1 : nTurns ;
var shading = parseCommaList( params.TURN_TRACK.SHADING ) ; var shadings = parseCommaList( params.TURN_TRACK.SHADING, true ) ;
var reinforce1 = parseCommaList( params.TURN_TRACK.REINFORCEMENTS_1 ) ; var reinforce1 = parseCommaList( params.TURN_TRACK.REINFORCEMENTS_1, false ) ;
var reinforce2 = parseCommaList( params.TURN_TRACK.REINFORCEMENTS_2 ) ; var reinforce2 = parseCommaList( params.TURN_TRACK.REINFORCEMENTS_2, false ) ;
return { return {
nTurns: nTurns, halfTurn: halfTurn, nTurns: nTurns, halfTurn: halfTurn,
vertical: vertical, width: width, shading: shading, vertical: vertical, width: width, shadings: shadings,
reinforce1: reinforce1, reinforce2: reinforce2 reinforce1: reinforce1, reinforce2: reinforce2
} ; } ;
} }

@ -1,12 +1,11 @@
DEFAULT_TURN_TRACK_TURNS_MIN = 6 ; DEFAULT_TURN_TRACK_TURNS_MIN = 6 ;
DEFAULT_TURN_TRACK_TURNS_MAX = 10 ; 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 :-/ // NOTE: Reinforcement flags get clipped on turn 100, but this is unlikely to be an issue :-/
_MAX_TURN_TRACK_TURNS = 100 ; _MAX_TURN_TRACK_TURNS = 100 ;
gTurnTrackReinforcements = null ; gTurnTrackReinforcements = null ;
gTurnTrackShading = null ; gTurnTrackShadings = null ;
// -------------------------------------------------------------------- // --------------------------------------------------------------------
@ -16,7 +15,7 @@ function editTurnTrackSettings()
var $dlg, $iframe, iframeSeqNo=0 ; 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 :-/ // FUDGE! This should work as a local variable, but causes a weird problem where it doesn't get reset properly :-/
gTurnTrackReinforcements = null ; gTurnTrackReinforcements = null ;
gTurnTrackShading = null ; gTurnTrackShadings = null ;
function loadControls() { function loadControls() {
// load the dialog controls // load the dialog controls
@ -37,7 +36,7 @@ function editTurnTrackSettings()
var params = updatePreview( false ) ; var params = updatePreview( false ) ;
var args = parseTurnTrackParams( params ) ; var args = parseTurnTrackParams( params ) ;
gTurnTrackReinforcements = { 1: args.reinforce1, 2: args.reinforce2 } ; gTurnTrackReinforcements = { 1: args.reinforce1, 2: args.reinforce2 } ;
gTurnTrackShading = args.shading ; gTurnTrackShadings = parseTurnTrackShadings( args.shadings ) ;
// update the UI // update the UI
updateUI() ; updateUI() ;
} }
@ -54,7 +53,7 @@ function editTurnTrackSettings()
$panel.find( "input[name='TURN_TRACK_REINFORCEMENTS_1']" ).val( "" ) ; $panel.find( "input[name='TURN_TRACK_REINFORCEMENTS_1']" ).val( "" ) ;
$panel.find( "input[name='TURN_TRACK_REINFORCEMENTS_2']" ).val( "" ) ; $panel.find( "input[name='TURN_TRACK_REINFORCEMENTS_2']" ).val( "" ) ;
gTurnTrackReinforcements = null ; gTurnTrackReinforcements = null ;
gTurnTrackShading = null ; gTurnTrackShadings = null ;
loadControls() ; loadControls() ;
} }
} ) ; } ) ;
@ -150,16 +149,27 @@ function editTurnTrackSettings()
function onShadingClick( turnNo ) { function onShadingClick( turnNo ) {
// NOTE: This method gets called by a click handler in the snippet HTML. // NOTE: This method gets called by a click handler in the snippet HTML.
// toggle the turn track square's shading // toggle the turn track square's shading
if ( gTurnTrackShading[turnNo] ) // determine the new shading strength
delete gTurnTrackShading[turnNo] ; var strength = gTurnTrackShadings[turnNo] || 0 ;
else var col ;
gTurnTrackShading[turnNo] = true ; if ( ++strength <= gAppConfig.TURN_TRACK_SHADING_COLORS.length ) {
$panel.find( "input[name='TURN_TRACK_SHADING']" ).val( gTurnTrackShadings[turnNo] = strength ;
Object.keys( gTurnTrackShading ).join( "," ) col = gAppConfig.TURN_TRACK_SHADING_COLORS[ strength-1 ] ;
) ; } else {
$iframe.contents().find( "#turn-square-" + turnNo ).css( { delete gTurnTrackShadings[turnNo] ;
"background-color": gTurnTrackShading && gTurnTrackShading[turnNo] ? TURN_TRACK_SHADING_COLOR : "inherit" col = "inherit" ;
}
// update the saved setting
var shadings = [] ;
Object.keys( gTurnTrackShadings ).forEach( function( key ) {
var strength = gTurnTrackShadings[key] ;
for ( var i=1 ; i < strength ; ++i )
key += "+" ;
shadings.push( key ) ;
} ) ; } ) ;
$panel.find( "input[name='TURN_TRACK_SHADING']" ).val( shadings.join( "," ) ) ;
// update the turn square in the UI
$iframe.contents().find( "#turn-square-" + turnNo ).css( { "background-color": col } ) ;
} }
function updateFlag( turnNo, playerNo ) { function updateFlag( turnNo, playerNo ) {
@ -322,6 +332,26 @@ function updateTurnTrackNTurns( nTurns )
} }
} }
function parseTurnTrackShadings( shadings ) {
// NOTE: A turn track shading setting consists of a number (the turn number),
// followed by 0 or more plus signs (to indicate a darker shading color).
var shadingTable = {} ;
shadings.forEach( function( shading ) {
var strength = 1 ;
while ( shading.length > 0 && shading.substr( shading.length-1 ) === "+" ) {
strength += 1 ;
shading = shading.substr( 0, shading.length-1 ) ;
}
if ( strength > gAppConfig.TURN_TRACK_SHADING_COLORS.length )
return ;
var turnNo = parseInt( shading ) ;
if ( isNaN( turnNo ) )
return ;
shadingTable[turnNo] = strength ;
} ) ;
return shadingTable ;
}
function formatTurnTrackOption( opt ) { function formatTurnTrackOption( opt ) {
// format the turn track <option> element // format the turn track <option> element
if ( opt.id === "(show-dialog)" ) if ( opt.id === "(show-dialog)" )

@ -1,5 +1,8 @@
""" Test the turn track functionality. """ """ Test the turn track functionality. """
import os
import re
from selenium.webdriver.support.ui import Select from selenium.webdriver.support.ui import Select
from selenium.webdriver.common.keys import Keys from selenium.webdriver.common.keys import Keys
@ -8,6 +11,13 @@ from vasl_templates.webapp.tests.utils import \
SwitchFrame, unload_table, wait_for, wait_for_elem, wait_for_clipboard, find_child SwitchFrame, unload_table, wait_for, wait_for_elem, wait_for_clipboard, find_child
from vasl_templates.webapp.tests.test_scenario_persistence import load_scenario, save_scenario from vasl_templates.webapp.tests.test_scenario_persistence import load_scenario, save_scenario
# extract the turn track shading colors
_TURN_TRACK_SHADING_COLORS = {}
with open( os.path.join( os.path.dirname(__file__), "../main.py" ), "r", encoding="ascii" ) as fp:
mo = re.search( r'"TURN_TRACK_SHADING_COLORS": \[ (.+) \]', fp.read(), flags=re.MULTILINE )
for mo2 in re.finditer( '"#[0-9a-f]{6}"', mo.group(1) ):
_TURN_TRACK_SHADING_COLORS[ mo2.group()[1:-1] ] = len(_TURN_TRACK_SHADING_COLORS) + 1
# --------------------------------------------------------------------- # ---------------------------------------------------------------------
def test_turn_track_basic( webapp, webdriver ): def test_turn_track_basic( webapp, webdriver ):
@ -141,8 +151,8 @@ def test_turn_track_shading( webapp, webdriver ):
_toggle_shading( 2 ) _toggle_shading( 2 )
_toggle_shading( 7 ) _toggle_shading( 7 )
assert _generate_turn_track_snippet( dlg ) == [ assert _generate_turn_track_snippet( dlg ) == [
[ (1,None,None,True), (2,None,None,True), (3,None,None), [ (1,None,None,"shading1"), (2,None,None,"shading1"), (3,None,None),
(4,None,None), (5,None,None) , (6,None,None), (7,None,None,True) (4,None,None), (5,None,None) , (6,None,None), (7,None,None,"shading1")
] ]
] ]
@ -152,8 +162,20 @@ def test_turn_track_shading( webapp, webdriver ):
_toggle_shading( 3 ) _toggle_shading( 3 )
_toggle_shading( 7 ) _toggle_shading( 7 )
assert _generate_turn_track_snippet( dlg ) == [ assert _generate_turn_track_snippet( dlg ) == [
[ (1,None,None), (2,None,None,True), (3,None,None,True), [ (1,None,None,"shading2"), (2,None,None,"shading1"), (3,None,None,"shading1"),
(4,None,None), (5,None,None) , (6,None,None), (7,None,None) (4,None,None), (5,None,None) , (6,None,None), (7,None,None,"shading2")
]
]
# 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( 2 )
_toggle_shading( 2 )
assert _generate_turn_track_snippet( dlg ) == [
[ (1,None,None), (2,None,None), (3,None,None,"shading2"),
(4,None,None), (5,None,None) , (6,None,None), (7,None,None,"shading2")
] ]
] ]
@ -181,6 +203,7 @@ def test_turn_track_persistence( webapp, webdriver ):
_toggle_reinf( 3, 2 ) _toggle_reinf( 3, 2 )
_toggle_shading( 2 ) _toggle_shading( 2 )
_toggle_shading( 4 ) _toggle_shading( 4 )
_toggle_shading( 4 )
_change_turn_track_width( dlg, 4 ) _change_turn_track_width( dlg, 4 )
_swap_turn_track_players( dlg ) _swap_turn_track_players( dlg )
_change_turn_track_direction( dlg ) _change_turn_track_direction( dlg )
@ -188,7 +211,7 @@ def test_turn_track_persistence( webapp, webdriver ):
# check the snippet # check the snippet
expected = [ expected = [
[ (1,None,"player2"), (3,"player1","player2"), (5,None,None), (7,None,None) ], [ (1,None,"player2"), (3,"player1","player2"), (5,None,None), (7,None,None) ],
[ (2,"player1",None,True) , (4,None,None,True), (6,None,None) ] [ (2,"player1",None,"shading1") , (4,None,None,"shading2"), (6,None,None) ]
] ]
wait_for( 2, wait_for( 2,
lambda: _generate_turn_track_snippet( dlg ) == expected lambda: _generate_turn_track_snippet( dlg ) == expected
@ -200,7 +223,7 @@ def test_turn_track_persistence( webapp, webdriver ):
assert saved_scenario["TURN_TRACK"] == { assert saved_scenario["TURN_TRACK"] == {
"NTURNS": "6.5", "NTURNS": "6.5",
"WIDTH": "4", "VERTICAL": True, "SWAP_PLAYERS": True, "WIDTH": "4", "VERTICAL": True, "SWAP_PLAYERS": True,
"SHADING": "2,4", "SHADING": "2,4+",
"REINFORCEMENTS_1": "2,3", "REINFORCEMENTS_2": "1,3", "REINFORCEMENTS_1": "2,3", "REINFORCEMENTS_2": "1,3",
} }
assert _generate_turn_track_snippet( None ) == expected assert _generate_turn_track_snippet( None ) == expected
@ -310,8 +333,15 @@ def _generate_turn_track_snippet( dlg ):
get_reinforce_class( cells[2] ), get_reinforce_class( cells[2] ),
) )
# check if the square is shaded # check if the square is shaded
if any( s.startswith( "background-color:" ) for s in square.xpath( ".//@style" ) ): cols = [ s for s in square.xpath( ".//@style" ) if s.startswith( "background-color:" ) ]
vals = ( *vals, True ) if cols:
assert len(cols) == 1
col = cols[0][17:]
assert col.endswith( ";" )
col = col[:-1]
shading = _TURN_TRACK_SHADING_COLORS.get( col )
assert shading, "Can't find turn track shading color: {}".format( shading )
vals = ( *vals, "shading{}".format( shading ) )
return vals return vals
# unload the snippet contents # unload the snippet contents

Loading…
Cancel
Save