" )
+def get_national_capabilities( nat, theater, year, month ):
+ """Get the national capabilities snippet."""
+ return render_template( "national-capabilities.html",
+ NATIONALITY = nat,
+ THEATER = theater,
+ YEAR = year,
+ MONTH = month
+ )
diff --git a/vasl_templates/webapp/snippets.py b/vasl_templates/webapp/snippets.py
index 5ea6799..419e14b 100644
--- a/vasl_templates/webapp/snippets.py
+++ b/vasl_templates/webapp/snippets.py
@@ -44,9 +44,10 @@ def load_default_template_pack(): #pylint: disable=too-many-locals
"default-template-pack/"
)
data = { "templates": {} }
- fname = os.path.join( base_dir, "nationalities.json" )
- with open(fname,"r") as fp:
+ with open( os.path.join( base_dir, "nationalities.json" ), "r") as fp:
data["nationalities"] = json.load( fp )
+ with open( os.path.join( base_dir, "national-capabilities.json" ), "r" ) as fp:
+ data["national-capabilities"] = json.load( fp )
# NOTE: Similarly, we always load the default extras templates, and user-defined template packs
# can add to them, or modify existing ones, but not remove them.
diff --git a/vasl_templates/webapp/static/css/tabs-scenario.css b/vasl_templates/webapp/static/css/tabs-scenario.css
index bab3952..bae2f7c 100644
--- a/vasl_templates/webapp/static/css/tabs-scenario.css
+++ b/vasl_templates/webapp/static/css/tabs-scenario.css
@@ -16,6 +16,9 @@
#panel-scenario label.header { font-weight: bold ; width: 3em ; text-align: center ; }
#panel-scenario input { margin-bottom: 0.25em ; }
+#panel-scenario #oba-info { height: 1em ; }
+.oba-info-tooltip { max-width: 500px ; }
+
#panel-scenario .select2-container { margin: 2px ; }
#panel-scenario .select2-selection__rendered { height: 23px ; line-height: 23px ; }
#panel-scenario .select2-selection__arrow { margin-top: -2px ; }
diff --git a/vasl_templates/webapp/static/css/tabs.css b/vasl_templates/webapp/static/css/tabs.css
index 19c3454..4317ba0 100644
--- a/vasl_templates/webapp/static/css/tabs.css
+++ b/vasl_templates/webapp/static/css/tabs.css
@@ -19,7 +19,7 @@
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#tabs-scenario { display: flex ; }
-#tabs-scenario .left { width: 33.5em ; min-width: 33.5em ; }
+#tabs-scenario .left { width: 32em ; min-width: 32em ; }
#tabs-scenario .right { flex-grow: 1 ; min-width: 25em ; }
#tabs-scenario .left { display: flex ; flex-direction: column ; }
diff --git a/vasl_templates/webapp/static/images/nat-caps.png b/vasl_templates/webapp/static/images/nat-caps.png
new file mode 100644
index 0000000..8b0a0ba
Binary files /dev/null and b/vasl_templates/webapp/static/images/nat-caps.png differ
diff --git a/vasl_templates/webapp/static/images/oba-info.png b/vasl_templates/webapp/static/images/oba-info.png
new file mode 100644
index 0000000..643ebe7
Binary files /dev/null and b/vasl_templates/webapp/static/images/oba-info.png differ
diff --git a/vasl_templates/webapp/static/main.js b/vasl_templates/webapp/static/main.js
index a48a7b7..e0622db 100644
--- a/vasl_templates/webapp/static/main.js
+++ b/vasl_templates/webapp/static/main.js
@@ -137,6 +137,12 @@ $(document).ready( function () {
onClose: on_scenario_date_change,
} ) ;
+ // initialize the OBA INFO tooltip
+ $( "#oba-info" ).tooltip( {
+ tooltipClass: "oba-info-tooltip",
+ content: make_oba_info_tooltip,
+ } ) ;
+
// initialize the SSR's
$("#ssr-sortable").sortable2( "init", {
add: add_ssr, edit: edit_ssr
@@ -394,6 +400,8 @@ $(document).ready( function () {
template_id = "ob_vehicles" ;
else if ( template_id.substring(0,12) === "ob_ordnance_" )
template_id = "ob_ordnance" ;
+ else if ( template_id.substring(0,9) === "nat_caps_" )
+ template_id = "nat_caps" ;
$( ""
@@ -415,14 +423,16 @@ function init_snippet_button( $btn )
var template_id2 ;
if ( template_id.substring(0,9) === "ob_setup_" )
template_id2 = "ob_setup" ;
- else if ( template_id.substring(0,21) == "ob_vehicles_ma_notes_" )
+ else if ( template_id.substring(0,21) === "ob_vehicles_ma_notes_" )
template_id2 = "ob_vehicles_ma_notes" ;
- else if ( template_id.substring(0,21) == "ob_ordnance_ma_notes_" )
+ else if ( template_id.substring(0,21) === "ob_ordnance_ma_notes_" )
template_id2 = "ob_ordnance_ma_notes" ;
- else if ( template_id.substring(0,12) == "ob_vehicles_" )
+ else if ( template_id.substring(0,12) === "ob_vehicles_" )
template_id2 = "ob_vehicles" ;
- else if ( template_id.substring(0,12) == "ob_ordnance_" )
+ else if ( template_id.substring(0,12) === "ob_ordnance_" )
template_id2 = "ob_ordnance" ;
+ else if ( template_id.substring(0,9) === "nat_caps_" )
+ template_id2 = "nat_caps" ;
else
template_id2 = template_id ;
@@ -435,12 +445,18 @@ function init_snippet_button( $btn )
""
] ;
var $newBtn = $( buf.join("") ) ;
- $newBtn.find( "button" ).prepend(
- $( "" )
- ).click( function( evt ) {
- generate_snippet( $(this), evt, null ) ;
- return false ;
- } ).attr( "title", GENERATE_SNIPPET_HINT ) ;
+ var fname="snippet.png", style="" ;
+ if ( template_id.substring( 0, 9 ) === "nat_caps_" ) {
+ fname = "nat-caps.png" ;
+ style = "height:15px;margin-right:0;" ;
+ }
+ $newBtn.find( "button" )
+ .prepend( $( "" ) )
+ .click( function( evt ) {
+ generate_snippet( $(this), evt, null ) ;
+ return false ;
+ } )
+ .attr( "title", GENERATE_SNIPPET_HINT ) ;
// add in the droplist
$newBtn.controlgroup() ;
@@ -514,6 +530,10 @@ function update_page_load_status( id )
$("#tabs").tabs({ disabled: [] }) ;
$("#loader").fadeOut( 500 ) ;
adjust_footer_vspacers() ;
+ // position the PLAYERS snippet button
+ var $btn = $( ".snippet-control[data-id='players']" ) ;
+ var $sel = $( ".select2[name='PLAYER_2_SAN']" ) ;
+ $btn.offset( { left: $sel.offset().left + $sel.outerWidth() - $btn.outerWidth() } ) ;
// NOTE: The watermark image appears briefly in IE when reloading the page, but not even
// creating the watermark dynamically and removing it when the page unloads fixes it :-(
$("#watermark").fadeIn( 5*1000 ) ;
@@ -717,6 +737,49 @@ function on_player_change( player_no )
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+function make_oba_info_tooltip()
+{
+ // initialize
+ var buf = [ "" ] ;
+ buf.push( "", " Off-Board Artillery" ) ;
+
+ // initialize
+ var params = {
+ SCENARIO_THEATER: $( "select.param[name='SCENARIO_THEATER']" ).val()
+ } ;
+ var scenario_date = get_scenario_date() ;
+ if ( scenario_date ) {
+ params.SCENARIO_MONTH = 1 + scenario_date.getMonth() ;
+ params.SCENARIO_YEAR = scenario_date.getFullYear() ;
+ }
+
+ // add the OBA info for each player
+ for ( var player_no=1 ; player_no <= 2 ; ++player_no ) {
+ buf.push( " |
" ) ;
+ var player_nat = $( "select[name='PLAYER_" + player_no + "']" ).val() ;
+ var display_name = get_nationality_display_name( player_nat ) ;
+ buf.push( "", display_name+":" ) ;
+ set_nat_caps_params( player_nat, params ) ;
+ if ( ! params.NAT_CAPS )
+ params.NAT_CAPS = { OBA_BLACK: "-", OBA_RED: "-" } ;
+ buf.push( " | " ) ;
+ var colors = [ "BLACK", "RED" ] ;
+ for ( var i=0 ; i < colors.length ; ++i ) {
+ var val = params.NAT_CAPS[ "OBA_"+colors[i] ] || "-" ;
+ buf.push( "", val, "" ) ;
+ }
+ if ( params.NAT_CAPS.OBA_COMMENTS ) {
+ for ( i=0 ; i < params.NAT_CAPS.OBA_COMMENTS.length ; ++i )
+ buf.push( " |
", "", " | ", params.NAT_CAPS.OBA_COMMENTS[i] ) ;
+ }
+ }
+
+ buf.push( " |
" ) ;
+ return buf.join( "" ) ;
+}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
function update_ob_tab_header( player_no )
{
// update the OB tab header for the specified player
@@ -741,6 +804,7 @@ function update_nationality_specific_buttons( player_no )
var theater = $( "select.param[name='SCENARIO_THEATER']" ).val().toLowerCase() ;
// hide/show each nationality-specific button
+ var $elem ;
for ( var button_id in NATIONALITY_SPECIFIC_BUTTONS ) {
var show = false ;
for ( var i=0 ; i < NATIONALITY_SPECIFIC_BUTTONS[button_id].length ; ++i ) {
@@ -755,9 +819,16 @@ function update_nationality_specific_buttons( player_no )
show = nat.substr(0,pos) == player_nat && nat.substr(pos+1) !== theater ;
}
}
- var $elem = $( "#panel-ob_notes_" + player_no + " div.snippet-control[data-id='" + button_id + "']" ) ;
+ $elem = $( "#panel-ob_notes_" + player_no + " div.snippet-control[data-id='" + button_id + "']" ) ;
$elem.css( "display", show ? "inline-block" : "none" ) ;
}
+
+ // update the CAPABILITIES button
+ var $btn = $( "button.generate[data-id='nat_caps_" + player_no + "']" ) ;
+ if ( get_national_capabilities( player_nat ) )
+ $btn.removeClass( "inactive" ) ;
+ else
+ $btn.addClass( "inactive" ) ;
}
// --------------------------------------------------------------------
diff --git a/vasl_templates/webapp/static/nat_caps.js b/vasl_templates/webapp/static/nat_caps.js
new file mode 100644
index 0000000..9462232
--- /dev/null
+++ b/vasl_templates/webapp/static/nat_caps.js
@@ -0,0 +1,117 @@
+// --------------------------------------------------------------------
+
+function set_nat_caps_params( player_nat, params )
+{
+ // get the national capabilities
+ var is_kfw = params.SCENARIO_THEATER == "Korea" ;
+ var nat_caps = get_national_capabilities( player_nat, is_kfw ) ;
+ if ( ! nat_caps )
+ return ;
+
+ // initialize
+ params.NAT_CAPS = {} ;
+ var excRegex = new RegExp( /\[EXC: .*?\]/g ) ;
+ var val ;
+
+ function add_nat_cap( key, val ) {
+ if ( val !== undefined )
+ params.NAT_CAPS[ key ] = val ;
+ }
+ function fixup_content( val ) {
+ val = strReplaceAll( val, "1st", "1st" ) ;
+ val = strReplaceAll( val, "2nd", "2nd" ) ;
+ return wrapSubstrings( val, excRegex, "", "" ) ;
+ }
+
+ // set the TH# color
+ if ( nat_caps.th_color ) {
+ if ( $.isArray( nat_caps.th_color ) ) {
+ add_nat_cap( "TH_COLOR",
+ make_time_based_comment( nat_caps.th_color[0], params.SCENARIO_MONTH, params.SCENARIO_YEAR ) + " TH#" +
+ " "
+ ) ;
+ } else {
+ var th_color = make_time_based_comment( nat_caps.th_color, params.SCENARIO_MONTH, params.SCENARIO_YEAR ) ;
+ var match = th_color.match( /\(.+\)$/ ) ;
+ if ( match )
+ th_color = th_color.substring(0,match.index) + "TH# " + match[0] ;
+ else
+ th_color += " TH#" ;
+ add_nat_cap( "TH_COLOR", th_color ) ;
+ }
+ }
+
+ // set the HoB DRM
+ if ( nat_caps.hob_drm ) {
+ if ( $.isArray( nat_caps.hob_drm ) ) {
+ add_nat_cap( "HOB_DRM",
+ nat_caps.hob_drm[0] +
+ " "
+ ) ;
+ } else {
+ add_nat_cap( "HOB_DRM", nat_caps.hob_drm ) ;
+ }
+ }
+
+ // set the type of grenades available
+ if ( nat_caps.grenades !== undefined ) {
+ val = (nat_caps.grenades === null) ? "No" : make_time_based_comment( nat_caps.grenades, params.SCENARIO_MONTH, params.SCENARIO_YEAR ) ;
+ add_nat_cap( "GRENADES", val+" grenades" ) ;
+ }
+
+ // set the OBA red/black numbers
+ if ( nat_caps.oba ) {
+ params.NAT_CAPS.OBA_BLACK = make_time_based_comment( nat_caps.oba[0], params.SCENARIO_MONTH, params.SCENARIO_YEAR ) ;
+ params.NAT_CAPS.OBA_RED = make_time_based_comment( nat_caps.oba[1], params.SCENARIO_MONTH, params.SCENARIO_YEAR ) ;
+ if ( nat_caps.oba.length > 2 ) {
+ var oba_comments = [] ;
+ for ( i=2 ; i < nat_caps.oba.length ; ++i ) {
+ val = make_time_based_comment( nat_caps.oba[i], params.SCENARIO_MONTH, params.SCENARIO_YEAR ) ;
+ if ( val )
+ oba_comments.push( val ) ;
+ }
+ if ( oba_comments.length > 0 )
+ params.NAT_CAPS.OBA_COMMENTS = oba_comments ;
+ }
+ }
+
+ // set the OBA access number
+ add_nat_cap( "OBA_ACCESS", nat_caps.oba_access ) ;
+
+ // add any additional notes
+ if ( nat_caps.notes ) {
+ params.NAT_CAPS.NOTES = [] ;
+ for ( i=0 ; i < nat_caps.notes.length ; ++i ) {
+ val = make_time_based_comment( nat_caps.notes[i], params.SCENARIO_MONTH, params.SCENARIO_YEAR ) ;
+ if ( val )
+ params.NAT_CAPS.NOTES.push( fixup_content( val ) ) ;
+ }
+ }
+}
+
+// --------------------------------------------------------------------
+
+function get_national_capabilities( nat, is_kfw )
+{
+ // get the capabilities for the specified nationality
+ if ( ! nat )
+ return null ;
+ if ( is_kfw ) {
+ if ( nat === "american" )
+ nat = "kfw-american" ;
+ else if ( ["british","british~canadian","british~newzealand"].indexOf( nat ) !== -1 )
+ nat = "kfw-bcfk" ;
+ }
+ else if ( nat === "anzac" || nat === "free-french" || nat.substring(0,8) === "british~" )
+ nat = "british" ;
+ var nat_caps = gTemplatePack["national-capabilities"][ nat ] ;
+ if ( nat_caps )
+ return nat_caps ;
+ if ( gTemplatePack.nationalities[ nat ] ) {
+ var nat_type = gTemplatePack.nationalities[ nat ].type ;
+ if ( nat_type )
+ return gTemplatePack["national-capabilities"][ nat_type ] ;
+ }
+ return null ;
+}
+
diff --git a/vasl_templates/webapp/static/snippets.js b/vasl_templates/webapp/static/snippets.js
index 062a31f..3d7b9ce 100644
--- a/vasl_templates/webapp/static/snippets.js
+++ b/vasl_templates/webapp/static/snippets.js
@@ -151,7 +151,11 @@ function make_snippet( $btn, params, extra_params, show_date_warnings )
params.PLAYER_FLAG_SIZE = "width='11' height='11'" ;
// set player-specific parameters
- var player_no = get_player_no_for_element( $btn ) ;
+ var player_no ;
+ if ( template_id.substring( 0, 9 ) === "nat_caps_" )
+ player_no = template_id.substring( 9 ) ;
+ else
+ player_no = get_player_no_for_element( $btn ) ;
var player_nat = get_player_nat( player_no ) ;
if ( player_no ) {
params.PLAYER_NAME = get_nationality_display_name( params["PLAYER_"+player_no] ) ;
@@ -213,6 +217,8 @@ function make_snippet( $btn, params, extra_params, show_date_warnings )
params.OB_VO_WIDTH = params.OB_ORDNANCE_WIDTH_2 ;
snippet_save_name = params.PLAYER_2 + " ordnance" ;
}
+ if ( template_id === "nat_caps_1" || template_id === "nat_caps_2" )
+ template_id = "nat_caps" ;
// adjust comments
adjust_vo_comments( params ) ;
@@ -242,12 +248,12 @@ function make_snippet( $btn, params, extra_params, show_date_warnings )
set_vo_note( "ordnance" ) ;
// generate snippets for multi-applicable vehicle/ordnance notes
- var pos ;
+ var pos, i ;
function add_ma_notes( ma_notes, keys, param_name, nat, vo_type ) {
if ( ! keys )
return ;
params[ param_name ] = [] ;
- for ( var i=0 ; i < keys.length ; ++i ) {
+ for ( i=0 ; i < keys.length ; ++i ) {
var ma_note = get_ma_note( nat, vo_type, keys[i] ) ;
var key = keys[i] ;
var extn_marker = "" ;
@@ -301,7 +307,7 @@ function make_snippet( $btn, params, extra_params, show_date_warnings )
template_id = "ob_" + vo_type + "_ma_notes" ;
var vo_type_uc = vo_type.toUpperCase() ;
var postfixes = [ "MA_NOTES", "MA_NOTES_WIDTH", "EXTRA_MA_NOTES", "EXTRA_MA_NOTES_CAPTION" ] ;
- for ( var i=0 ; i < postfixes.length ; ++i ) {
+ for ( i=0 ; i < postfixes.length ; ++i ) {
params[ "OB_" + postfixes[i] ] = params[ "OB_" + vo_type_uc + "_" + postfixes[i] + "_" + player_no ] ;
}
snippet_save_name = params["PLAYER_"+player_no] + (vo_type === "vehicles" ? " vehicle notes" : " ordnance notes") ;
@@ -371,6 +377,9 @@ function make_snippet( $btn, params, extra_params, show_date_warnings )
params.BAZ_RANGE = 4 ;
}
+ // set the national capabilities parameters
+ set_nat_caps_params( player_nat, params ) ;
+
// check for mandatory parameters
if ( template_id in _MANDATORY_PARAMS ) {
var missing_params = [] ;
@@ -432,7 +441,7 @@ function make_snippet( $btn, params, extra_params, show_date_warnings )
snippet = func( params, {
autoEscape: false,
filters: {
- join: function( vals, sep ) { return vals.join( sep ) ; },
+ join: function( vals, sep ) { return vals ? vals.join(sep) : "" ; },
nbsp: function( val ) { return strReplaceAll( val, " ", " " ) ; },
} ,
} ) ;
@@ -484,20 +493,14 @@ function adjust_vo_comments( params )
}
// allow comment EXC's to be styled
- var excRegex = new RegExp( /\[EXC: .*?\]/ ) ;
+ var excRegex = new RegExp( /\[EXC: .*?\]/g ) ;
function adjustExc( val ) {
- var match = val.match( excRegex ) ;
- if ( match ) {
- val = val.substring( 0, match.index ) +
- "" + match[0] + "" +
- val.substring( match.index + match[0].length ) ;
- }
- return val ;
+ return wrapSubstrings( val, excRegex, "", "" ) ;
}
// adjust comments
if ( params.OB_VO ) {
- for ( var i=0 ; i < params.OB_VO.length ; ++i ) {
+ for ( i=0 ; i < params.OB_VO.length ; ++i ) {
if ( ! params.OB_VO[i].comments )
continue ;
for ( var j=0 ; j < params.OB_VO[i].comments.length ; ++j ) {
@@ -935,40 +938,10 @@ function get_vo_comments( vo_entry, month, year )
if ( ! vo_entry.comments )
return vo_entry.comments ;
- function parseDate( val ) {
- if ( ! val )
- return null ;
- var match = val.trim().match( /^(\d\d)\/(19\d\d)$/ ) ;
- if ( ! match )
- return null ;
- return [ match[1], match[2] ] ;
- }
-
// generate the vehicle/ordnance's comments
var voComments=[], cmt, i ;
for ( i=0 ; i < vo_entry.comments.length ; ++i ) {
- cmt = vo_entry.comments[i] ;
- if ( cmt.substr(0,2) === "{?" && cmt.substr(cmt.length-2) === "?}" ) {
- // this is a time-based comment, check the scenario date
- var words = cmt.substring( 2, cmt.length-2 ).split( "|" ) ;
- var dates = words[0].split( "-" ) ;
- dates = [ parseDate(dates[0]), parseDate(dates[1]) ] ;
- if ( words.length != 4 || dates.length != 2 || (!dates[0] && !dates[1]) ) {
- showErrorMsg( "Invalid time-based vehicle/ordnance comment: " + cmt ) ;
- continue ;
- }
- if ( !month || !year )
- cmt = words[3] ;
- else {
- var rc = true ;
- if ( dates[0] && ( year < dates[0][1] || ( year == dates[0][1] && month < dates[0][0] ) ) )
- rc = false ;
- if ( dates[1] && ( year > dates[1][1] || ( year == dates[1][1] && month > dates[1][0] ) ) )
- rc = false ;
- cmt = rc ? words[1] : words[2] ;
- }
- }
- cmt = cmt.trim() ;
+ cmt = make_time_based_comment( vo_entry.comments[i], month, year ) ;
if ( cmt )
voComments.push( cmt ) ;
}
@@ -996,6 +969,108 @@ function get_vo_comments( vo_entry, month, year )
return voComments ;
}
+function make_time_based_comment( val, month, year )
+{
+ function parseDateControl( val ) {
+ // parse a date control string
+ var dates = val.split( "-" ) ;
+ if ( dates.length != 2 )
+ return null ;
+ for ( var i=0 ; i < 2 ; ++i ) {
+ var date = dates[i].trim() ;
+ if ( date !== "" ) {
+ var match = date.match( /^(\d\d)\/(19\d\d)$/ ) ;
+ if ( ! match )
+ return null ;
+ dates[i] = [ match[1], match[2] ] ;
+ } else {
+ dates[i] = null ;
+ }
+ }
+ return dates ;
+ }
+ function checkDateControl( dateControl ) {
+ // check if the date passed in falls within the date control
+ if ( dateControl[0] && ( year < dateControl[0][1] || ( year == dateControl[0][1] && month < dateControl[0][0] ) ) )
+ return false ;
+ if ( dateControl[1] && ( year > dateControl[1][1] || ( year == dateControl[1][1] && month > dateControl[1][0] ) ) )
+ return false ;
+ return true ;
+ }
+
+ // process any time-based values
+ var words, dateControl ;
+ for ( ; ; ) {
+
+ // check for a time-based substitution
+ var parts = findDelimitedSubstring( val, "{?", "?}" ) ;
+ if ( $.isArray( parts ) ) {
+ // found one - this form has the following syntax:
+ // {? DATE CONTROL | within the date control | outside the date control | fallback text ?}
+ // parse the date control
+ words = parts[1].split( "|" ) ;
+ dateControl = parseDateControl( words[0] ) ;
+ if ( words.length != 4 || dateControl === null ) {
+ showErrorMsg( "Invalid time-based comment: " + val ) ;
+ return null ;
+ }
+ // figure out which value to use
+ if ( month && year )
+ val = parts[0] + words[ checkDateControl(dateControl) ? 1 : 2 ].trim() + parts[2] ;
+ else
+ val = parts[0] + words[3].trim() + parts[2] ;
+ continue ;
+ }
+
+ // check for a time-based substitution
+ parts = findDelimitedSubstring( val, "{!", "!}" ) ;
+ if ( $.isArray( parts ) ) {
+ // found one - this form has the following syntax:
+ // {! DATE CONTROL = text | DATE CONTROL = text | etc... | fallback text !}
+ var fallbackText = "" ;
+ choices = parts[1].split( "|" ) ;
+ for ( var i=0 ; i < choices.length ; ++i ) {
+ // parse the next choice
+ var pos = choices[i].indexOf( "=" ) ;
+ if ( pos !== -1 ) {
+ dateControl = parseDateControl( choices[i].substring( 0, pos ) ) ;
+ if ( dateControl !== null ) {
+ // the choice is valid - save it, and its substitution text
+ choices[i] = [ dateControl, choices[i].substring(pos+1).trim() ] ;
+ continue ;
+ }
+ }
+ // the choice is invalid
+ if ( i === choices.length-1 ) {
+ // this is the last choice - use it as the fallback text
+ fallbackText = choices.pop().trim() ;
+ break ;
+ } else {
+ showErrorMsg( "Invalid time-based comment: " + choices[i] ) ;
+ return null ;
+ }
+ }
+ // check each choice to try find a match
+ var replaceText = fallbackText ;
+ if ( month && year ) {
+ for ( i=0 ; i < choices.length ; ++i ) {
+ if ( checkDateControl( choices[i][0] ) ) {
+ // found a match - replace the content with the substitution text
+ replaceText = choices[i][1] ;
+ break ;
+ }
+ }
+ }
+ val = parts[0] + replaceText + parts[2] ;
+ }
+
+ // NOTE: If we get here, there are no more time-based substitutions to be made.
+ break ;
+ }
+
+ return val ;
+}
+
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
function make_capabilities( raw, vo_entry, vo_type, nat, elite, scenario_theater, scenario_year, scenario_month, show_warnings )
@@ -1937,6 +2012,7 @@ function do_load_template_pack( fname, data )
var unknown_template_ids = [] ;
var template_pack = {
nationalities: $.extend( true, {}, gDefaultTemplatePack.nationalities ),
+ "national-capabilities": $.extend( true, {}, gDefaultTemplatePack["national-capabilities"] ),
templates: {},
css: {},
includes: {},
@@ -1963,6 +2039,17 @@ function do_load_template_pack( fname, data )
$.extend( true, template_pack.nationalities, nationalities ) ;
return ;
}
+ if ( fname.toLowerCase() === "national-capabilities.json" ) {
+ var nat_caps = null ;
+ try {
+ nat_caps = JSON.parse( data ) ;
+ } catch( ex ) {
+ showWarningMsg( "Can't parse the nationalities JSON data:" + escapeHTML(ex) + "
" ) ;
+ return ;
+ }
+ $.extend( true, template_pack["national-capabilities"], nat_caps ) ;
+ return ;
+ }
var extn = getFilenameExtn( fname ) ;
if ( [".j2",".css",".include"].indexOf( extn ) === -1 ) {
invalid_filename_extns.push( fname ) ;
diff --git a/vasl_templates/webapp/static/sortable.js b/vasl_templates/webapp/static/sortable.js
index 2d3b52f..815f713 100644
--- a/vasl_templates/webapp/static/sortable.js
+++ b/vasl_templates/webapp/static/sortable.js
@@ -77,7 +77,7 @@ $.fn.sortable2 = function( action, args )
$sortable2.data( "no_confirm_delete", args.no_confirm_delete ) ;
$sortable2.data( "on_edit", args.edit ) ;
var $add_btn = find_helper( $sortable2, "add" ) ;
- $add_btn.prepend( $( " Add
" ) )
+ $add_btn.prepend( $( " Add
" ) )
.button( {} ) ;
var $add = find_helper( $sortable2, "add" ) ;
$add.prop( "title", "Add a new " + display_name[0] )
@@ -85,7 +85,7 @@ $.fn.sortable2 = function( action, args )
if ( args.reset ) {
$sortable2.data( "on_reset", args.reset ) ;
var $reset_btn = find_helper( $sortable2, "reset" ) ;
- $reset_btn.prepend( $( " Reset
" ) )
+ $reset_btn.prepend( $( " Reset
" ) )
.button( {} ) ;
var $reset = find_helper( $sortable2, "reset" ) ;
$reset.prop( "title", "Reset the " + display_name[1] )
diff --git a/vasl_templates/webapp/static/user_settings.js b/vasl_templates/webapp/static/user_settings.js
index 4a72225..275c15e 100644
--- a/vasl_templates/webapp/static/user_settings.js
+++ b/vasl_templates/webapp/static/user_settings.js
@@ -9,6 +9,7 @@ USER_SETTINGS = {
"date-format": "droplist",
"scenario-images-source": "droplist",
"hide-unavailable-ma-notes": "checkbox",
+ "auto-create-national-capabilities-labels": "checkbox",
"include-vasl-images-in-snippets": "checkbox",
"include-flags-in-snippets": "checkbox",
"custom-list-bullets": "checkbox",
@@ -76,7 +77,7 @@ function user_settings()
dialogClass: "user-settings",
modal: true,
width: 460,
- height: 320,
+ height: 340,
resizable: false,
create: function() {
init_dialog( $(this), "OK", true ) ;
diff --git a/vasl_templates/webapp/static/utils.js b/vasl_templates/webapp/static/utils.js
index 72fed09..5e2f4d6 100644
--- a/vasl_templates/webapp/static/utils.js
+++ b/vasl_templates/webapp/static/utils.js
@@ -4,6 +4,8 @@
function get_nationality_display_name( nat_id )
{
// get the nationality's display name
+ if ( ! gTemplatePack.nationalities[ nat_id ] )
+ return null ;
return gTemplatePack.nationalities[ nat_id ].display_name ;
}
@@ -85,6 +87,8 @@ function is_template_available( template_id )
// check if the specified template is available
if ( template_id.match( /^ob_(vehicles|ordnance).*_[12]$/ ) )
template_id = template_id.substring( 0, template_id.length-2 ) ;
+ else if ( template_id === "nat_caps_1" || template_id === "nat_caps_2" )
+ template_id = "nat_caps" ;
return gTemplatePack.templates[ template_id ] !== undefined ;
}
@@ -426,6 +430,42 @@ function strReplaceAll( val, searchFor, replaceWith )
}
}
+function findDelimitedSubstring( val, delim1, delim2 )
+{
+ // search for a substring delimited by the 2 specified markers
+ if ( val === null || val === undefined )
+ return null ;
+ var pos = val.indexOf( delim1 ) ;
+ if ( pos === -1 )
+ return val ;
+ var pos2 = val.indexOf( delim2, pos ) ;
+ if ( pos2 === -1 )
+ return val ;
+ // found it - return the prefix/middle/postfix parts
+ return [
+ val.substring( 0, pos ),
+ val.substring( pos+delim1.length, pos2 ),
+ val.substring( pos2+delim2.length )
+ ] ;
+}
+
+function wrapSubstrings( val, searchFor, delim1, delim2 )
+{
+ // search for a substring and wrap it with the specified delimeters
+ if ( val === null || val === undefined )
+ return null ;
+ // FUDGE! matchAll() isn't available in the PyQt embedded browser :-/
+ var matches = [] ;
+ while ( ( match = searchFor.exec( val ) ) !== null )
+ matches.push( match ) ;
+ for ( var i=matches.length-1 ; i >= 0 ; --i ) {
+ val = val.substring( 0, matches[i].index ) +
+ delim1 + matches[i][0] + delim2 +
+ val.substring( matches[i].index + matches[i][0].length ) ;
+ }
+ return val ;
+}
+
function getFilenameExtn( fname )
{
// get the filename extension
diff --git a/vasl_templates/webapp/static/vassal.js b/vasl_templates/webapp/static/vassal.js
index 9d4fc82..4d62962 100644
--- a/vasl_templates/webapp/static/vassal.js
+++ b/vasl_templates/webapp/static/vassal.js
@@ -100,6 +100,10 @@ function _generate_snippets()
}
no_autocreate[template_id] = true ;
}
+ if ( ! gUserSettings["auto-create-national-capabilities-labels"] ) {
+ no_autocreate.nat_caps_1 = true ;
+ no_autocreate.nat_caps_2 = true ;
+ }
function on_snippet_button( $btn, inactive ) {
var template_id = $btn.attr( "data-id" ) ;
@@ -114,7 +118,11 @@ function _generate_snippets()
var params = unload_snippet_params( true, template_id ) ;
var snippet_id = template_id ;
var extra_params = {} ;
- var player_no = get_player_no_for_element( $btn ) ;
+ var player_no ;
+ if ( snippet_id.substring( 0, 9 ) === "nat_caps_" )
+ player_no = snippet_id.substring( 9 ) ;
+ else
+ player_no = get_player_no_for_element( $btn ) ;
var data ;
if ( ["scenario_note","ob_setup","ob_note"].indexOf( template_id ) !== -1 ) {
data = $btn.parent().parent().data( "sortable2-data" ) ;
@@ -225,6 +233,8 @@ function _get_raw_content( snippet_id, $btn, params )
return [ "Bazooka", "Range", "TH#" ] ;
if ( snippet_id === "thh" )
return [ "Tank-Hunter Heroes", "Banzai Charge" ] ;
+ if ( snippet_id.substring( 0, 9 ) === "nat_caps_" )
+ return [ "Capabilities" ] ;
// handle vehicle/ordnance notes
// NOTE: These were implemented after we added snippet ID's, so there's no need to support legacy labels.
diff --git a/vasl_templates/webapp/templates/index.html b/vasl_templates/webapp/templates/index.html
index 3f434f4..06a36dc 100644
--- a/vasl_templates/webapp/templates/index.html
+++ b/vasl_templates/webapp/templates/index.html
@@ -110,6 +110,7 @@ gHelpUrl = "{{url_for('show_help')}}" ;
+
diff --git a/vasl_templates/webapp/templates/national-capabilities.html b/vasl_templates/webapp/templates/national-capabilities.html
new file mode 100644
index 0000000..58df26c
--- /dev/null
+++ b/vasl_templates/webapp/templates/national-capabilities.html
@@ -0,0 +1,70 @@
+
+
+
+
+
+ National Capabilities: {{NATIONALITY}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/vasl_templates/webapp/templates/tabs-scenario.html b/vasl_templates/webapp/templates/tabs-scenario.html
index a294121..1146d6d 100644
--- a/vasl_templates/webapp/templates/tabs-scenario.html
+++ b/vasl_templates/webapp/templates/tabs-scenario.html
@@ -41,16 +41,19 @@
+
+
-
-
-
+
+
+
+
diff --git a/vasl_templates/webapp/templates/user-settings-dialog.html b/vasl_templates/webapp/templates/user-settings-dialog.html
index a0ddc5e..5fc3215 100644
--- a/vasl_templates/webapp/templates/user-settings-dialog.html
+++ b/vasl_templates/webapp/templates/user-settings-dialog.html
@@ -5,7 +5,10 @@
- Hide unavailable multi-applicable notes
+ Auto-create National Capabilities labels
+
+ Hide unavailable multi-applicable notes
+