Allow vehicles/ordnance to be marked as Elite.

master
Pacman Ghost 5 years ago
parent 6969c5c228
commit 3344cdf083
  1. 1
      .pylintrc
  2. 2
      vasl_templates/webapp/data/default-template-pack/ob_ordnance.j2
  3. 2
      vasl_templates/webapp/data/default-template-pack/ob_vehicles.j2
  4. 42
      vasl_templates/webapp/static/snippets.js
  5. 18
      vasl_templates/webapp/static/vo.js
  6. 32
      vasl_templates/webapp/static/vo2.js
  7. 6
      vasl_templates/webapp/templates/edit-vo-dialog.html
  8. 4
      vasl_templates/webapp/templates/vo-report.html
  9. 143
      vasl_templates/webapp/tests/test_capabilities.py

@ -140,6 +140,7 @@ disable=print-statement,
wrong-import-position,
global-statement,
too-few-public-methods,
too-many-lines,
duplicate-code, # can't get it to shut up about @pytest.mark.skipif's :-/
no-else-return

@ -26,7 +26,7 @@ sup { font-size: 75% ; }
{%for ord in OB_ORDNANCE%}
<tr style="border-bottom:1px dotted #e0e0e0;">
<td valign="top" style="padding:2px 5px 5px;">
<b> {{ord.name}} </b>
<b>{{ord.name}}</b> {%if ord.elite%}&#x24ba;{%endif%}
{%if ord.image%} <br> <img src="{{ord.image}}"> {%endif%}
<div class="note">
{%if ord.extn_id%} &#x2756; {%endif%}

@ -26,7 +26,7 @@ sup { font-size: 75% ; }
{%for veh in OB_VEHICLES%}
<tr style="border-bottom:1px dotted #e0e0e0;">
<td valign="top" style="padding:2px 5px 5px;">
<b> {{veh.name}} </b>
<b>{{veh.name}}</b> {%if veh.elite%}&#x24ba;{%endif%}
{%if veh.image%} <br> <img src="{{veh.image}}"> {%endif%}
<div class="note">
{%if veh.extn_id%} &#x2756; {%endif%}

@ -648,11 +648,13 @@ function unload_snippet_params( unpack_scenario_date, template_id )
var $sortable2 = $( "#ob_" + vo_type + "-sortable_" + player_no ) ;
var objs = [] ;
$sortable2.children( "li" ).each( function() {
var vo_entry = $(this).data( "sortable2-data" ).vo_entry ;
var vo_image_id = $(this).data( "sortable2-data" ).vo_image_id ;
var data = $(this).data( "sortable2-data" ) ;
var vo_entry = data.vo_entry ;
var vo_image_id = data.vo_image_id ;
var elite = data.elite ;
var obj = {
id: vo_entry.id,
seq_id: $(this).data( "sortable2-data" ).id,
seq_id: data.id,
image_id: (vo_image_id !== null) ? vo_image_id[0]+"/"+vo_image_id[1] : null,
name: vo_entry.name,
note_number: vo_entry.note_number,
@ -682,7 +684,7 @@ function unload_snippet_params( unpack_scenario_date, template_id )
// we will show the warnings when we make the raw capabilities.
capabilities = make_capabilities(
false,
vo_entry, nat,
vo_entry, nat, elite,
params.SCENARIO_THEATER, params.SCENARIO_YEAR, params.SCENARIO_MONTH,
false
) ;
@ -691,12 +693,15 @@ function unload_snippet_params( unpack_scenario_date, template_id )
}
capabilities = make_capabilities(
true,
vo_entry, nat,
vo_entry, nat, elite,
params.SCENARIO_THEATER, params.SCENARIO_YEAR, params.SCENARIO_MONTH,
show_warnings
) ;
if ( capabilities )
if ( capabilities ) {
obj.raw_capabilities = capabilities ;
if ( elite )
obj.elite = true ;
}
var comments = $(this).data( "sortable2-data" ).custom_comments ;
if ( comments ) {
obj.comments = comments ;
@ -719,7 +724,7 @@ function unload_snippet_params( unpack_scenario_date, template_id )
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
function make_capabilities( raw, vo_entry, nat, scenario_theater, scenario_year, scenario_month, show_warnings )
function make_capabilities( raw, vo_entry, nat, elite, scenario_theater, scenario_year, scenario_month, show_warnings )
{
var capabilities = [] ;
@ -835,6 +840,10 @@ function make_capabilities( raw, vo_entry, nat, scenario_theater, scenario_year,
capabilities2.push( capabilities[i] ) ;
}
// check for elite vehicles/ordnance
if ( elite )
adjust_capabilities_for_elite( capabilities2, +1 ) ;
return capabilities2 ;
}
@ -1017,6 +1026,21 @@ function make_crew_survival( vo_entry )
return crew_survival ;
}
function adjust_capabilities_for_elite( capabilities, delta )
{
// adjust the list of capabilities for elite status
// Pondicherry, India (FEB/19)
if ( ! capabilities )
return ;
for ( var i=0 ; i < capabilities.length ; ++i ) {
if ( capabilities[i].indexOf( "<sup>" ) !== -1 )
continue ; // nb: ignore raw capabilities (e.g. if the scenario date hasn't been set)
var match = capabilities[i].match( /^(A|M|H|C|D|HE|AP|WP|s|S|sD|sM|sN)([1-9][0-9]?)/ ) ;
if ( match )
capabilities[i] = match[1] + (parseInt(match[2]) + delta) + capabilities[i].substr(match[1].length+match[2].length) ;
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
function get_template( template_id, fixup )
@ -1256,7 +1280,7 @@ function do_load_scenario_data( params )
warnings.push( "Invalid V/O image ID for '" + params[key][i].name + "': " + params[key][i].image_id ) ;
}
if ( vo_entry )
do_add_vo( vo_type, player_no, vo_entry, vo_image_id, params[key][i].custom_capabilities, params[key][i].custom_comments, params[key][i].seq_id ) ;
do_add_vo( vo_type, player_no, vo_entry, vo_image_id, params[key][i].elite, params[key][i].custom_capabilities, params[key][i].custom_comments, params[key][i].seq_id ) ;
else
unknown_vo.push( vo_id || "(not set)" ) ;
}
@ -1415,6 +1439,8 @@ function unload_params_for_save( user_requested )
entry.image_id = params[key][i].image_id ;
if ( params[key][i].custom_capabilities )
entry.custom_capabilities = params[key][i].custom_capabilities ;
if ( params[key][i].elite )
entry.elite = true ;
if ( params[key][i].custom_comments )
entry.custom_comments = params[key][i].custom_comments ;
entries.push( entry ) ;

@ -111,7 +111,7 @@ function add_vo( vo_type, player_no )
var $img = $elem.find( "img[class='vasl-image']" ) ;
var vo_image_id = $img.data( "vo-image-id" ) ;
var seq_id = auto_assign_id( usedSeqIds, "seq_id" ) ;
do_add_vo( vo_type, player_no, sel_entry, vo_image_id, null, null, seq_id ) ;
do_add_vo( vo_type, player_no, sel_entry, vo_image_id, false, null, null, seq_id ) ;
$dlg.dialog( "close" ) ;
}
if ( usedVoIds.indexOf( sel_entry.id ) !== -1 ) {
@ -131,7 +131,7 @@ function add_vo( vo_type, player_no )
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
function do_add_vo( vo_type, player_no, vo_entry, vo_image_id, custom_capabilities, custom_comments, seq_id )
function do_add_vo( vo_type, player_no, vo_entry, vo_image_id, elite, custom_capabilities, custom_comments, seq_id )
{
// add the specified vehicle/ordnance
// NOTE: We set a fixed height for the sortable2 entries (based on the CSS settings in tabs-ob.css),
@ -149,6 +149,7 @@ function do_add_vo( vo_type, player_no, vo_entry, vo_image_id, custom_capabiliti
caption: vo_entry.name,
vo_entry: vo_entry,
vo_image_id: vo_image_id,
elite: elite,
fixed_height: fixed_height
} ;
if ( custom_capabilities )
@ -208,9 +209,10 @@ function update_vo_sortable2_entry( $entry, snippet_params )
// initialize
if ( ! snippet_params )
snippet_params = unload_snippet_params( true, null ) ;
var vo_entry = $entry.data( "sortable2-data" ).vo_entry ;
var vo_image_id = $entry.data( "sortable2-data" ).vo_image_id ;
var capabilities = $entry.data( "sortable2-data" ).custom_capabilities ;
var data = $entry.data( "sortable2-data" ) ;
var vo_entry = data.vo_entry ;
var vo_image_id = data.vo_image_id ;
var capabilities = data.custom_capabilities ;
if ( capabilities )
capabilities = capabilities.slice() ;
else {
@ -219,6 +221,7 @@ function update_vo_sortable2_entry( $entry, snippet_params )
false,
vo_entry,
snippet_params[ "PLAYER_"+player_no ],
data.elite,
snippet_params.SCENARIO_THEATER, snippet_params.SCENARIO_YEAR, snippet_params.SCENARIO_MONTH,
false
) ;
@ -228,7 +231,10 @@ function update_vo_sortable2_entry( $entry, snippet_params )
var url = get_vo_image_url( vo_entry, vo_image_id, true ) ;
var $content = $entry.children( ".vo-entry" ) ;
$content.find( "img.vasl-image" ).attr( "src", url ) ;
$content.find( "div.vo-name" ).html( vo_entry.name ) ;
var name = vo_entry.name ;
if ( data.elite )
name += " \u24ba" ;
$content.find( "div.vo-name" ).html( name ) ;
for ( var i=0 ; i < capabilities.length ; ++i )
capabilities[i] = "<span class='vo-capability'>" + capabilities[i] + "</span>" ;
$content.find( "div.vo-capabilities" ).html( capabilities.join("") ) ;

@ -11,6 +11,7 @@ function _do_edit_ob_vo( $entry, player_no, vo_type )
false,
vo_entry,
params[ "PLAYER_"+player_no ],
false,
params.SCENARIO_THEATER, params.SCENARIO_YEAR, params.SCENARIO_MONTH,
show_warnings
) ;
@ -34,12 +35,23 @@ function _do_edit_ob_vo( $entry, player_no, vo_type )
return entries ;
}
function make_vo_name( name, elite ) {
if ( elite )
name += " \u24ba" ;
else {
if ( name.substr( name.length-2 ) === " \u24ba" )
name = name.substr( 0, name.length-2 ) ;
}
return name ;
}
// get the vehicle/ordnance's capabilities/comments
var params = unload_snippet_params( true, null ) ;
var vo_entry = $entry.data( "sortable2-data" ).vo_entry ;
var capabilities = $entry.data( "sortable2-data" ).custom_capabilities ;
if ( ! capabilities )
capabilities = get_default_capabilities( vo_entry, params, true ).slice() ;
var elite = $entry.data( "sortable2-data" ).elite ;
var comments = $entry.data( "sortable2-data" ).custom_comments ;
if ( ! comments )
comments = get_default_comments( vo_entry ) ;
@ -50,7 +62,7 @@ function _do_edit_ob_vo( $entry, player_no, vo_type )
var buf = [ "<div class='header'>",
"<img src='" + url + "' class='vasl-image'>",
"<div class='content'>",
"<span class='vo-name'>" + vo_entry.name + "</span>",
"<span class='vo-name'>" + make_vo_name( vo_entry.name, elite ) + "</span>",
"</div>",
"</div" ] ;
$header = $( buf.join("") ) ;
@ -71,6 +83,7 @@ function _do_edit_ob_vo( $entry, player_no, vo_type )
// initialize
var $capabilities = $( "#vo_capabilities-sortable" ) ;
var $elite = $( "#edit-vo .capabilities input.elite" ) ;
var $comments = $( "#vo_comments-sortable" ) ;
function add_entry( $sortable, val, visible ) {
var $elem = $( "<div>" +
@ -96,9 +109,11 @@ function _do_edit_ob_vo( $entry, player_no, vo_type )
var $reset_capabilities = $( "#vo_capabilities-reset" ) ;
$reset_capabilities.data( { vo_entry: vo_entry, params: params } ) ;
function on_reset_capabilities() {
$dlg.find( ".header .vo-name" ).html( make_vo_name( vo_entry.name, elite ) ) ;
load_entries( $capabilities,
get_default_capabilities( $reset_capabilities.data("vo_entry"), $reset_capabilities.data("params"), false )
) ;
$elite.prop( "checked", false ) ;
}
var $reset_comments = $( "#vo_comments-reset" ) ;
$reset_comments.data( { vo_entry: vo_entry, params: params } ) ;
@ -108,6 +123,16 @@ function _do_edit_ob_vo( $entry, player_no, vo_type )
) ;
}
function update_for_elite( delta ) {
// update the capabilities
var capabilities = unload_entries( $capabilities ) ;
adjust_capabilities_for_elite( capabilities, delta ) ;
load_entries( $capabilities, capabilities ) ;
// update the vehicle/ordnance name
var $name = $( "#edit-vo .header .vo-name" ) ;
$name.html( make_vo_name( $name.html(), delta > 0 ) ) ;
}
// show the dialog
var $dlg = $( "#edit-vo" ).dialog( {
dialogClass: "edit-vo",
@ -128,6 +153,9 @@ function _do_edit_ob_vo( $entry, player_no, vo_type )
reset: on_reset_comments,
no_confirm_delete: true,
} ) ;
$elite.click( function() {
update_for_elite( $(this).prop( "checked" ) ? +1 : -1 ) ;
} ) ;
},
open: function() {
// initialize
@ -141,6 +169,7 @@ function _do_edit_ob_vo( $entry, player_no, vo_type )
} ) ;
// load the dialog
load_entries( $capabilities, capabilities ) ;
$elite.prop( "checked", elite ? true : false ) ;
load_entries( $comments, comments ) ;
},
buttons: {
@ -158,6 +187,7 @@ function _do_edit_ob_vo( $entry, player_no, vo_type )
// the capabilities are the same as the default - no need to retain these custom settings
delete $entry.data( "sortable2-data" ).custom_capabilities ;
}
$entry.data( "sortable2-data" ).elite = $elite.prop( "checked" ) ;
// unload the comments
var comments = unload_entries( $comments ) ;
if ( comments.join() !== get_default_comments( vo_entry ).join() ) {

@ -3,7 +3,11 @@
<div class="header"></div>
<div class="capabilities">
<div class="fieldset-legend">Capabilities:</div>
<div class="fieldset-legend">
Capabilities:
<div style="float:right;"> <input type="checkbox" class="elite">&nbsp;Elite </input> </div>
<br clear="all">
</div>
<div class="fieldset">
<ul id="vo_capabilities-sortable" class="sortable"></ul>
<div class="footer">

@ -67,9 +67,9 @@ function load_vo_listings( objs )
continue ;
buf.push( "<tr>" ) ;
buf.push( "<td>", fmtval(obj.name) ) ;
var capabilities = make_capabilities( true, obj, nat, theater, year, month, true ) ;
var capabilities = make_capabilities( true, obj, nat, false, theater, year, month, true ) ;
buf.push( "<td>", listval(capabilities) ) ;
var capabilities = make_capabilities( false, obj, nat, theater, year, month, true ) ;
var capabilities = make_capabilities( false, obj, nat, false, theater, year, month, true ) ;
buf.push( "<td>", listval(capabilities) ) ;
buf.push( "<td>", "<span class='val'>" + fmtval(obj.note_number) + "</span>" ) ;
buf.push( "<td>", listval(obj.notes) ) ;

@ -840,6 +840,149 @@ def test_capability_updates_in_ui( webapp, webdriver ):
# ---------------------------------------------------------------------
def test_elite( webapp, webdriver ): #pylint: disable=too-many-statements
"""Test elite vehicles/ordnance."""
# initialize
init_webapp( webapp, webdriver, scenario_persistence=1,
reset = lambda ct:
ct.set_data_dir( dtype="real" )
)
def get_sortable_elem():
"""Find the sortable element for the test vehicle."""
sortable = find_child( "#ob_vehicles-sortable_1" )
elems = find_children( "li", sortable )
assert len(elems) == 1
return elems[0]
def check_elite( expected, custom ):
"""Check the elite status of the vehicle in the main UI."""
vo_name = find_child( ".vo-name", get_sortable_elem() ).text
caps = [ c.text for c in find_children(".vo-capability",get_sortable_elem()) ]
if expected:
assert vo_name.endswith( "\u24ba" )
expected = [ "A62", "M8\u2020", "sD8", "CS 6" ]
if custom:
expected.append( "HE11" )
assert caps == expected
else:
assert "\u24ba" not in vo_name
expected = [ "A62", "M7\u2020", "sD7", "CS 6" ]
if custom:
expected.append( "HE10" )
assert caps == expected
def check_elite2( expected, custom ):
"""Check the elite status of the vehicle in the edit dialog."""
vo_name = find_child( "#edit-vo .header .vo-name" ).text
caps = [ c.get_attribute("value") for c in find_children("#vo_capabilities-sortable input[type='text']") ]
if expected:
assert vo_name.endswith( "\u24ba" )
expected = [ "A6<sup>2</sup>", "M8\u2020", "sD8", "CS 6" ]
if custom:
expected.append( "HE11" )
assert caps == expected
else:
assert "\u24ba" not in vo_name
expected = [ "A6<sup>2</sup>", "M7\u2020", "sD7", "CS 6" ]
if custom:
expected.append( "HE10" )
assert caps == expected
# load the scenario
scenario_data = {
"PLAYER_1": "german",
"OB_VEHICLES_1": [ { "name": "PzKpfw VIE" } ], # A6[2] M7 sD7
}
load_scenario( scenario_data )
select_tab( "ob1" )
# check that the vehicle was loaded non-elite
check_elite( False, False )
# add a custom capability
ActionChains(webdriver).double_click( get_sortable_elem() ).perform()
elem = find_child( "#vo_capabilities-add" )
elem.click()
elems = find_children( "#vo_capabilities-sortable input[type='text']" )
assert len(elems) == 5
elems[4].send_keys( "HE10" )
click_dialog_button( "OK" )
# make the vehicle elite
ActionChains(webdriver).double_click( get_sortable_elem() ).perform()
check_elite2( False, True )
elem = find_child( "#edit-vo .capabilities .elite" )
elem.click()
check_elite2( True, True )
click_dialog_button( "OK" )
check_elite( True, True )
# save the scenario, then reload it
saved_scenario = save_scenario()
assert len(saved_scenario["OB_VEHICLES_1"]) == 1
assert saved_scenario["OB_VEHICLES_1"][0]["elite"]
assert saved_scenario["OB_VEHICLES_1"][0]["custom_capabilities"] == \
[ "A6<sup>2</sup>", "M8\u2020", "sD8", "CS 6", "HE11" ]
select_menu_option( "new_scenario" )
load_scenario( saved_scenario )
select_tab( "ob1" )
check_elite( True, True )
# make the vehicle non-elite
ActionChains(webdriver).double_click( get_sortable_elem() ).perform()
check_elite2( True, True )
elem = find_child( "#edit-vo .capabilities .elite" )
elem.click()
check_elite2( False, True )
click_dialog_button( "OK" )
check_elite( False, True )
# save the scenario
saved_scenario = save_scenario()
assert len(saved_scenario["OB_VEHICLES_1"]) == 1
assert "elite" not in saved_scenario["OB_VEHICLES_1"][0]
assert saved_scenario["OB_VEHICLES_1"][0]["custom_capabilities"] == \
[ "A6<sup>2</sup>", "M7\u2020", "sD7", "CS 6", "HE10" ]
# make the vehicle elite, remove the custom capability
ActionChains(webdriver).double_click( get_sortable_elem() ).perform()
check_elite2( False, True )
elem = find_child( "#edit-vo .capabilities .elite" )
elem.click()
check_elite2( True, True )
elems = find_children( "#vo_capabilities-sortable li" )
webdriver.execute_script( "arguments[0].scrollIntoView(true);", elems[4] )
ActionChains(webdriver).key_down( Keys.CONTROL ).click( elems[4] ).key_up( Keys.CONTROL ).perform()
click_dialog_button( "OK" )
check_elite( True, False )
# save the scenario, then reload it
saved_scenario = save_scenario()
assert len(saved_scenario["OB_VEHICLES_1"]) == 1
assert saved_scenario["OB_VEHICLES_1"][0]["elite"]
assert saved_scenario["OB_VEHICLES_1"][0]["custom_capabilities"] == [ "A6<sup>2</sup>", "M8\u2020", "sD8", "CS 6" ]
select_menu_option( "new_scenario" )
load_scenario( saved_scenario )
select_tab( "ob1" )
check_elite( True, False )
# make the vehicle non-elite
ActionChains(webdriver).double_click( get_sortable_elem() ).perform()
check_elite2( True, False )
elem = find_child( "#edit-vo .capabilities .elite" )
elem.click()
check_elite2( False, False )
click_dialog_button( "OK" )
check_elite( False, False )
# save the scenario
saved_scenario = save_scenario()
assert len(saved_scenario["OB_VEHICLES_1"]) == 1
assert "elite" not in saved_scenario["OB_VEHICLES_1"][0]
assert "custom_capabilities" not in saved_scenario["OB_VEHICLES_1"][0]
# ---------------------------------------------------------------------
def _check_capabilities( webdriver, webapp,
nat, vo_type, vo_name, scenario_theater, scenario_date,
expected, row=None

Loading…
Cancel
Save