diff --git a/Dockerfile b/Dockerfile
index 7a98f73..3c7e41c 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -7,6 +7,8 @@
# -p 5010:5010 \
# -v .../vasl-6.4.3.vmod:/data/vasl.vmod \
# vasl-templates
+# If you have Chapter H data, add the following:
+# -v .../chapter-h-notes:/data/chapter-h-notes
FROM python:alpine3.6
diff --git a/conftest.py b/conftest.py
index a593fbd..510a16e 100644
--- a/conftest.py
+++ b/conftest.py
@@ -62,6 +62,13 @@ def pytest_addoption( parser ):
help="Directory containing VASSAL installation(s)."
)
+ # NOTE: Some tests require Chapter H vehicle/ordnance notes. This is copyrighted material,
+ # so it is kept in a private repo.
+ parser.addoption(
+ "--vo-notes", action="store", dest="vo_notes", default=None,
+ help="Directory containing Chapter H vehicle/ordnance notes and test results."
+ )
+
# NOTE: It's not good to have the code run differently to how it will normally,
# but using the clipboard to retrieve snippets causes more trouble than it's worth :-/
# since any kind of clipboard activity while the tests are running could cause them to fail
diff --git a/docker/config/site.cfg b/docker/config/site.cfg
index 27869ca..54816ee 100644
--- a/docker/config/site.cfg
+++ b/docker/config/site.cfg
@@ -3,3 +3,4 @@
FLASK_HOST = 0.0.0.0
VASL_MOD = /data/vasl.vmod
+CHAPTER_H_NOTES = /data/chapter-h-notes/
diff --git a/vasl_templates/webapp/__init__.py b/vasl_templates/webapp/__init__.py
index 9d1715c..1ab2a5d 100644
--- a/vasl_templates/webapp/__init__.py
+++ b/vasl_templates/webapp/__init__.py
@@ -60,6 +60,7 @@ import vasl_templates.webapp.vo #pylint: disable=cyclic-import
import vasl_templates.webapp.snippets #pylint: disable=cyclic-import
import vasl_templates.webapp.files #pylint: disable=cyclic-import
import vasl_templates.webapp.vassal #pylint: disable=cyclic-import
+import vasl_templates.webapp.vo_notes #pylint: disable=cyclic-import
if app.config.get( "ENABLE_REMOTE_TEST_CONTROL" ):
print( "*** WARNING: Remote test control enabled! ***" )
import vasl_templates.webapp.testing #pylint: disable=cyclic-import
diff --git a/vasl_templates/webapp/config/site.cfg.example b/vasl_templates/webapp/config/site.cfg.example
index ef2e777..f17cc08 100644
--- a/vasl_templates/webapp/config/site.cfg.example
+++ b/vasl_templates/webapp/config/site.cfg.example
@@ -8,3 +8,5 @@ VASSAL_DIR = ...configure the VASSAL installation directory...
BOARDS_DIR = ...configure the VASL boards directory...
WEBDRIVER_PATH = ...configure either geckodriver or chromedriver here...
; JAVA_PATH = ...configure the Java executable here (optional, must be in the PATH otherwise)...
+
+CHAPTER_H_NOTES = ...configure your Chapter H vehicle/ordnance images and multi-applicable notes...
diff --git a/vasl_templates/webapp/data/default-scenario.json b/vasl_templates/webapp/data/default-scenario.json
index f43d380..09f52f6 100644
--- a/vasl_templates/webapp/data/default-scenario.json
+++ b/vasl_templates/webapp/data/default-scenario.json
@@ -12,6 +12,11 @@
"VICTORY_CONDITIONS_WIDTH": "300px",
"SSR_WIDTH": "300px",
+"OB_VEHICLES_MA_NOTES_WIDTH_1": "300px",
+"OB_ORDNANCE_MA_NOTES_WIDTH_1": "300px",
+"OB_VEHICLES_MA_NOTES_WIDTH_2": "300px",
+"OB_ORDNANCE_MA_NOTES_WIDTH_2": "300px",
+
"_SCENARIO_NOTE_WIDTH": "200px"
}
diff --git a/vasl_templates/webapp/data/default-template-pack/nationalities.json b/vasl_templates/webapp/data/default-template-pack/nationalities.json
index 6583428..402fde0 100644
--- a/vasl_templates/webapp/data/default-template-pack/nationalities.json
+++ b/vasl_templates/webapp/data/default-template-pack/nationalities.json
@@ -47,48 +47,58 @@
"polish": {
"display_name": "Polish",
- "ob_colors": [ "#a3ecd1","#82e3bd", "#61d8a6" ]
+ "ob_colors": [ "#a3ecd1","#82e3bd", "#61d8a6" ],
+ "type": "allied-minor"
},
"belgian": {
"display_name": "Belgian",
- "ob_colors": [ "#a3ecd1","#82e3bd", "#61d8a6" ]
+ "ob_colors": [ "#a3ecd1","#82e3bd", "#61d8a6" ],
+ "type": "allied-minor"
},
"yugoslavian": {
"display_name": "Yugoslavian",
- "ob_colors": [ "#a3ecd1","#82e3bd", "#61d8a6" ]
+ "ob_colors": [ "#a3ecd1","#82e3bd", "#61d8a6" ],
+ "type": "allied-minor"
},
"danish": {
"display_name": "Danish",
- "ob_colors": [ "#a3ecd1","#82e3bd", "#61d8a6" ]
+ "ob_colors": [ "#a3ecd1","#82e3bd", "#61d8a6" ],
+ "type": "allied-minor"
},
"dutch": {
"display_name": "Dutch",
- "ob_colors": [ "#a3ecd1","#82e3bd", "#61d8a6" ]
+ "ob_colors": [ "#a3ecd1","#82e3bd", "#61d8a6" ],
+ "type": "allied-minor"
},
"greek": {
"display_name": "Greek",
- "ob_colors": [ "#a3ecd1","#82e3bd", "#61d8a6" ]
+ "ob_colors": [ "#a3ecd1","#82e3bd", "#61d8a6" ],
+ "type": "allied-minor"
},
-
"romanian": {
"display_name": "Romanian",
- "ob_colors": [ "#3ceb7c","#1de256", "#0ed93c" ]
+ "ob_colors": [ "#3ceb7c","#1de256", "#0ed93c" ],
+ "type": "axis-minor"
},
"hungarian": {
"display_name": "Hungarian",
- "ob_colors": [ "#3ceb7c","#1de256", "#0ed93c" ]
+ "ob_colors": [ "#3ceb7c","#1de256", "#0ed93c" ],
+ "type": "axis-minor"
},
"slovakian": {
"display_name": "Slovakian",
- "ob_colors": [ "#3ceb7c","#1de256", "#0ed93c" ]
+ "ob_colors": [ "#3ceb7c","#1de256", "#0ed93c" ],
+ "type": "axis-minor"
},
"croatian": {
"display_name": "Croatian",
- "ob_colors": [ "#3ceb7c","#1de256", "#0ed93c" ]
+ "ob_colors": [ "#3ceb7c","#1de256", "#0ed93c" ],
+ "type": "axis-minor"
},
"bulgarian": {
"display_name": "Bulgarian",
- "ob_colors": [ "#3ceb7c","#1de256", "#0ed93c" ]
+ "ob_colors": [ "#3ceb7c","#1de256", "#0ed93c" ],
+ "type": "axis-minor"
}
}
diff --git a/vasl_templates/webapp/data/default-template-pack/ob_ordnance_ma_notes.j2 b/vasl_templates/webapp/data/default-template-pack/ob_ordnance_ma_notes.j2
new file mode 100644
index 0000000..2024f61
--- /dev/null
+++ b/vasl_templates/webapp/data/default-template-pack/ob_ordnance_ma_notes.j2
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
+
+
+
+
+ {%if PLAYER_FLAG%} {%endif%}{{PLAYER_NAME}} Ordnance Notes
+
+{%if OB_ORDNANCE_MA_NOTES%}
+ |
+{%for ma_note in OB_ORDNANCE_MA_NOTES%}
+ {{ma_note}}
+{%endfor%}
+{%endif%}
+
+{%if OB_ORDNANCE_EXTRA_MA_NOTES%}
+ |
+{%if OB_ORDNANCE_EXTRA_MA_NOTES_CAPTION%} {%endif%}
+{%for ma_note in OB_ORDNANCE_EXTRA_MA_NOTES%}
+ {{ma_note}}
+{%endfor%}
+{%endif%}
+
+ |
+
+
diff --git a/vasl_templates/webapp/data/default-template-pack/ob_ordnance_note.j2 b/vasl_templates/webapp/data/default-template-pack/ob_ordnance_note.j2
new file mode 100644
index 0000000..f87db92
--- /dev/null
+++ b/vasl_templates/webapp/data/default-template-pack/ob_ordnance_note.j2
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
+
+ {%if PLAYER_FLAG%} {%endif%}{{ORDNANCE_NAME}}
+
+ |
+
+
+ |
+
+
diff --git a/vasl_templates/webapp/data/default-template-pack/ob_vehicle_note.j2 b/vasl_templates/webapp/data/default-template-pack/ob_vehicle_note.j2
new file mode 100644
index 0000000..85eb718
--- /dev/null
+++ b/vasl_templates/webapp/data/default-template-pack/ob_vehicle_note.j2
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
+
+ {%if PLAYER_FLAG%} {%endif%}{{VEHICLE_NAME}}
+
+ |
+
+
+ |
+
+
diff --git a/vasl_templates/webapp/data/default-template-pack/ob_vehicles_ma_notes.j2 b/vasl_templates/webapp/data/default-template-pack/ob_vehicles_ma_notes.j2
new file mode 100644
index 0000000..724dfca
--- /dev/null
+++ b/vasl_templates/webapp/data/default-template-pack/ob_vehicles_ma_notes.j2
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
+
+
+
+
+ {%if PLAYER_FLAG%} {%endif%}{{PLAYER_NAME}} Vehicle Notes
+
+{%if OB_VEHICLES_MA_NOTES%}
+ |
+{%for ma_note in OB_VEHICLES_MA_NOTES%}
+ {{ma_note}}
+{%endfor%}
+{%endif%}
+
+{%if OB_VEHICLES_EXTRA_MA_NOTES%}
+ |
+{%if OB_VEHICLES_EXTRA_MA_NOTES_CAPTION%} {%endif%}
+{%for ma_note in OB_VEHICLES_EXTRA_MA_NOTES%}
+ {{ma_note}}
+{%endfor%}
+{%endif%}
+
+ |
+
+
diff --git a/vasl_templates/webapp/data/ordnance/chinese.json b/vasl_templates/webapp/data/ordnance/chinese.json
index c3837a9..047415a 100644
--- a/vasl_templates/webapp/data/ordnance/chinese.json
+++ b/vasl_templates/webapp/data/ordnance/chinese.json
@@ -167,7 +167,7 @@
"capabilities": [ "NT", "QSU", "h-d" ],
"capabilities2": { "WP": 7, "C": "5\u20201" },
"note_number": "10\u2020",
- "notes": [ "A", "C \u20201" ],
+ "notes": [ "A", "C\u20201" ],
"id": "ch/o:019",
"gpid": 2037
},
diff --git a/vasl_templates/webapp/files.py b/vasl_templates/webapp/files.py
index 5d1e099..e285e5a 100644
--- a/vasl_templates/webapp/files.py
+++ b/vasl_templates/webapp/files.py
@@ -15,6 +15,27 @@ if app.config.get( "VASL_MOD" ):
# ---------------------------------------------------------------------
+class FileServer:
+ """Serve static files."""
+
+ def __init__( self, base_dir ):
+ self.base_dir = os.path.abspath( base_dir )
+
+ def get_file( self, fname ):
+ """Serve a file."""
+ if not fname:
+ return None
+ fname = os.path.join( self.base_dir, fname )
+ fname = os.path.abspath( fname )
+ if not os.path.isfile( fname ):
+ return None
+ prefix = os.path.commonpath( [ self.base_dir, fname ] )
+ if prefix != self.base_dir:
+ return None # nb: files must be sub-ordinate to the configured directory
+ return fname
+
+# ---------------------------------------------------------------------
+
def install_vasl_mod( new_vasl_mod ):
"""Install a new VASL module."""
global vasl_mod
diff --git a/vasl_templates/webapp/static/css/sortable.css b/vasl_templates/webapp/static/css/sortable.css
index f5bed89..fd6f886 100644
--- a/vasl_templates/webapp/static/css/sortable.css
+++ b/vasl_templates/webapp/static/css/sortable.css
@@ -17,4 +17,4 @@ img.sortable-reset { vertical-align: middle ; height: 15px ; margin-right: 0.25e
.sortable-hint .instructions { margin: 1em 0 0 1em ; font-size: 80% ; font-style: italic ; color: #888 ; }
.sortable-hint .instructions li { margin-top: 0.5em ; }
-.sortable-trash { margin: 3px 5px ; height: 24px ; }
+.sortable-trash { margin: 3px 5px 0 5px ; height: 24px ; }
diff --git a/vasl_templates/webapp/static/css/tabs-ob.css b/vasl_templates/webapp/static/css/tabs-ob.css
index 52e7ca2..e6e3f9f 100644
--- a/vasl_templates/webapp/static/css/tabs-ob.css
+++ b/vasl_templates/webapp/static/css/tabs-ob.css
@@ -2,33 +2,32 @@
.panel-ob_setups { height: 100% ; display: flex ; flex-direction: column ; }
.panel-ob_setups .content { flex-grow: 1 ; }
-.panel-ob_setups .sortable { font-size: 90% ; }
-.panel-ob_setups .footer { margin-top: 0.5em ; display: flex ; align-items: center ; }
+.panel-ob_setups .footer { margin-top: 0.5em ; padding-bottom: 1px ; display: flex ; align-items: center ; }
/* -------------------------------------------------------------------- */
.panel-ob_notes { height: 100% ; display: flex ; flex-direction: column ; }
.panel-ob_notes .content { flex-grow: 1 ; }
-.panel-ob_notes .sortable { font-size: 90% ; }
-.panel-ob_notes .footer { margin-top: 0.5em ; display: flex ; align-items: center ; }
+.panel-ob_notes .footer { margin-top: 0.5em ; padding-bottom: 1px ; display: flex ; align-items: center ; }
/* -------------------------------------------------------------------- */
.panel-ob_vehicles { height: 100% ; display: flex ; flex-direction: column ; }
.panel-ob_vehicles .content { flex-grow: 1 ; }
-.panel-ob_vehicles .sortable { font-size: 90% ; }
.panel-ob_vehicles .footer { margin-top: 0.5em ; display: flex ; align-items: center ; }
.panel-ob_ordnance { height: 100% ; display: flex ; flex-direction: column ; }
.panel-ob_ordnance .content { flex-grow: 1 ; }
-.panel-ob_ordnance .sortable { font-size: 90% ; }
.panel-ob_ordnance .footer { margin-top: 0.5em ; display: flex ; align-items: center ; }
/* nb: the following CSS is shared by vehicles and ordnance */
-.panel-ob_vo .sortable .vo-entry { display: flex ; font-size: 90% ; }
-.panel-ob_vo .sortable .vo-entry img.vasl-image { display: inline-block ; vertical-align: middle ; height: 3.5em ; margin-right: 0.5em ; }
-.panel-ob_vo .sortable .vo-entry.small-piece img.vasl-image { height: 2.5em ; margin-left: 0.5em ; margin-right: 1em ; }
+.panel-ob_vo .sortable .vo-entry { display: flex ; }
+.panel-ob_vo .sortable .vo-entry img.vasl-image { display: inline-block ; vertical-align: middle ; height: 3.25em ; margin-right: 0.5em ; }
+.panel-ob_vo .sortable .vo-entry.small-piece img.vasl-image { height: 2.25em ; margin-left: 0.5em ; margin-right: 0.75em ; }
.panel-ob_vo .sortable .vo-entry .detail { flex-grow: 1 ; display: flex ; flex-direction: column ; justify-content: center ; }
-.panel-ob_vo .sortable .vo-entry .detail .vo-name { font-size: 110% ; }
-.panel-ob_vo .sortable .vo-entry .detail .vo-capabilities { max-height: 2.5em ; overflow: hidden ; font-size: 90% ; font-style: italic ; }
+.panel-ob_vo .sortable .vo-entry .detail .vo-name { font-size: 90% ; }
+.panel-ob_vo .sortable .vo-entry .detail .vo-capabilities { max-height: 2.5em ; overflow: hidden ; font-size: 80% ; font-style: italic ; }
.panel-ob_vo .sortable .vo-entry .detail .vo-capability { margin-right: 0.5em ; color: #444 ; }
+.panel-ob_vo label.header { font-weight: bold ; display: inline-block ; width: 3.25em ; }
+.panel-ob_vo .snippet-admin { align-self: flex-end ; }
+.panel-ob_vo .snippets-notes { margin-top: 2px ; }
diff --git a/vasl_templates/webapp/static/css/tabs.css b/vasl_templates/webapp/static/css/tabs.css
index dd8010b..4317ba0 100644
--- a/vasl_templates/webapp/static/css/tabs.css
+++ b/vasl_templates/webapp/static/css/tabs.css
@@ -34,7 +34,7 @@
.ui-tabs-panel.tabs-ob { display: flex ; }
.ui-tabs-panel.tabs-ob .left { flex-grow: 1 ; min-width: 32em ; }
-.ui-tabs-panel.tabs-ob .right { width: 25em ; min-width: 25em ; }
+.ui-tabs-panel.tabs-ob .right { width: 28em ; min-width: 26em ; }
.ui-tabs-panel.tabs-ob .left { display: flex ; flex-direction: column ; }
.ui-tabs-panel.tabs-ob .tl { height: 100% ; flex-grow: 1 }
diff --git a/vasl_templates/webapp/static/main.js b/vasl_templates/webapp/static/main.js
index 4b98b74..0e670c0 100644
--- a/vasl_templates/webapp/static/main.js
+++ b/vasl_templates/webapp/static/main.js
@@ -4,6 +4,7 @@ gDefaultTemplatePack = null ;
gTemplatePack = {} ;
gValidTemplateIds = [] ;
gVehicleOrdnanceListings = {} ;
+gVehicleOrdnanceNotes = {} ;
gVaslPieceInfo = {} ;
gWebChannelHandler = null ;
@@ -239,6 +240,18 @@ $(document).ready( function () {
} ).fail( function( xhr, status, errorMsg ) {
showErrorMsg( "Can't get the ordnance listings:" + escapeHTML(errorMsg) + "
" ) ;
} ) ;
+ $.getJSON( gVehicleNotesUrl, function(data) {
+ gVehicleOrdnanceNotes.vehicles = data ;
+ update_page_load_status( "vehicle-notes" ) ;
+ } ).fail( function( xhr, status, errorMsg ) {
+ showErrorMsg( "Can't get the vehicle notes:" + escapeHTML(errorMsg) + "
" ) ;
+ } ) ;
+ $.getJSON( gOrdnanceNotesUrl, function(data) {
+ gVehicleOrdnanceNotes.ordnance = data ;
+ update_page_load_status( "ordnance-notes" ) ;
+ } ).fail( function( xhr, status, errorMsg ) {
+ showErrorMsg( "Can't get the ordnance notes:" + escapeHTML(errorMsg) + "
" ) ;
+ } ) ;
// get the VASL piece info
$.getJSON( gGetVaslPieceInfoUrl, function(data) {
@@ -355,6 +368,10 @@ $(document).ready( function () {
var template_id = $(this).attr( "data-id" ) ;
if ( template_id.substring(0,9) === "ob_setup_" )
template_id = "ob_setup" ;
+ else if ( template_id.substring(0,21) === "ob_vehicles_ma_notes_" )
+ template_id = "ob_vehicles_ma_notes" ;
+ else if ( template_id.substring(0,21) === "ob_ordnance_ma_notes_" )
+ template_id = "ob_ordnance_ma_notes" ;
else if ( template_id.substring(0,12) === "ob_vehicles_" )
template_id = "ob_vehicles" ;
else if ( template_id.substring(0,12) === "ob_ordnance_" )
@@ -380,6 +397,10 @@ 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_" )
+ template_id2 = "ob_vehicles_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_" )
template_id2 = "ob_vehicles" ;
else if ( template_id.substring(0,12) == "ob_ordnance_" )
@@ -426,7 +447,7 @@ function init_snippet_button( $btn )
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-gPageLoadStatus = [ "main", "vehicle-listings", "ordnance-listings", "vasl-piece-info", "template-pack", "default-scenario" ] ;
+gPageLoadStatus = [ "main", "vehicle-listings", "ordnance-listings", "vehicle-notes", "ordnance-notes", "vasl-piece-info", "template-pack", "default-scenario" ] ;
function update_page_load_status( id )
{
@@ -587,6 +608,18 @@ function on_player_change( player_no )
}
}
+ // show/hide the vehicle/ordnance multi-applicable notes controls
+ function update_ma_notes_controls( vo_type ) {
+ var show = ( gVehicleOrdnanceNotes[vo_type] && gVehicleOrdnanceNotes[vo_type][player_nat] ) ||
+ ["allied-minor","axis-minor"].indexOf( gTemplatePack.nationalities[ player_nat ].type ) !== -1 ;
+ var $fieldset = $( "#tabs-ob" + player_no + " fieldset[name='ob_" + vo_type + "_" + player_no ) ;
+ $fieldset.find( ".snippets-notes" ).css( "display", show?"block":"none" ) ;
+ $fieldset.find( "label[for='ob']" ).css( "display", show?"inline-block":"none" ) ;
+ }
+ update_ma_notes_controls( "vehicles" ) ;
+ update_ma_notes_controls( "ordnance" ) ;
+ // TO DO: We should also show a button that lets the ob_vehicle/ordnance_note template to be edited.
+
// reset the OB params
$( "#ob_setups-sortable_" + player_no ).sortable2( "delete-all" ) ;
$("input[name='OB_SETUP_WIDTH_"+player_no+"']").val( "" ) ;
diff --git a/vasl_templates/webapp/static/simple_notes.js b/vasl_templates/webapp/static/simple_notes.js
index c12fd10..d618b0d 100644
--- a/vasl_templates/webapp/static/simple_notes.js
+++ b/vasl_templates/webapp/static/simple_notes.js
@@ -93,7 +93,7 @@ function _do_edit_simple_note( $sortable2, $entry, default_width )
$sortable2.find( "li" ).each( function() {
usedIds[ $(this).data("sortable2-data").id ] = true ;
} ) ;
- data.id = auto_assign_id( usedIds ) ;
+ data.id = auto_assign_id( usedIds, "id" ) ;
}
_do_add_simple_note( $sortable2, data ) ;
}
@@ -126,7 +126,7 @@ function _make_simple_note( note_type, caption )
if ( ["scenario_notes","ob_setups","ob_notes"].indexOf( note_type ) !== -1 ) {
var note_type0 = note_type.substring( 0, note_type.length-1 ) ;
buf.push(
- ""
) ;
}
diff --git a/vasl_templates/webapp/static/snippets.js b/vasl_templates/webapp/static/snippets.js
index 120b9e1..23d2edb 100644
--- a/vasl_templates/webapp/static/snippets.js
+++ b/vasl_templates/webapp/static/snippets.js
@@ -24,7 +24,9 @@ var gScenarioCreatedTime = null ;
function generate_snippet( $btn, extra_params )
{
// generate the snippet
- var snippet = make_snippet( $btn, extra_params, true ) ;
+ var template_id = $btn.data( "id" ) ;
+ var params = unload_snippet_params( true, template_id ) ;
+ var snippet = make_snippet( $btn, params, extra_params, true ) ;
// copy the snippet to the clipboard
try {
@@ -37,11 +39,10 @@ function generate_snippet( $btn, extra_params )
showInfoMsg( "The HTML snippet has been copied to the clipboard." ) ;
}
-function make_snippet( $btn, extra_params, show_date_warnings )
+function make_snippet( $btn, params, extra_params, show_date_warnings )
{
// initialize
var template_id = $btn.data( "id" ) ;
- var params = unload_snippet_params( true, template_id ) ;
// set player-specific parameters
var player_no = get_player_no_for_element( $btn ) ;
@@ -56,7 +57,7 @@ function make_snippet( $btn, extra_params, show_date_warnings )
// set the snippet ID
var data ;
- if ( template_id === "ob_setup" || template_id === "ob_note" ) {
+ if ( ["ob_setup","ob_note","ob_vehicle_note","ob_ordnance_note"].indexOf( template_id ) !== -1 ) {
data = $btn.parent().parent().data( "sortable2-data" ) ;
params.SNIPPET_ID = template_id + "_" + player_no + "." + data.id ;
} else if ( template_id === "scenario_note" ) {
@@ -66,25 +67,101 @@ function make_snippet( $btn, extra_params, show_date_warnings )
params.SNIPPET_ID = template_id ;
// set player-specific parameters
- if ( template_id == "ob_vehicles_1" ) {
+ if ( template_id === "ob_vehicles_1" ) {
template_id = "ob_vehicles" ;
params.OB_VEHICLES = params.OB_VEHICLES_1 ;
params.OB_VEHICLES_WIDTH = params.OB_VEHICLES_WIDTH_1 ;
- } else if ( template_id == "ob_vehicles_2" ) {
+ } else if ( template_id === "ob_vehicles_2" ) {
template_id = "ob_vehicles" ;
params.OB_VEHICLES = params.OB_VEHICLES_2 ;
params.OB_VEHICLES_WIDTH = params.OB_VEHICLES_WIDTH_2 ;
}
- if ( template_id == "ob_ordnance_1" ) {
+ if ( template_id === "ob_ordnance_1" ) {
template_id = "ob_ordnance" ;
params.OB_ORDNANCE = params.OB_ORDNANCE_1 ;
params.OB_ORDNANCE_WIDTH = params.OB_ORDNANCE_WIDTH_1 ;
- } else if ( template_id == "ob_ordnance_2" ) {
+ } else if ( template_id === "ob_ordnance_2" ) {
template_id = "ob_ordnance" ;
params.OB_ORDNANCE = params.OB_ORDNANCE_2 ;
params.OB_ORDNANCE_WIDTH = params.OB_ORDNANCE_WIDTH_2 ;
}
+ // set vehicle/ordnance note parameters
+ function set_vo_note( vo_type ) {
+ var data = $btn.parent().parent().data( "sortable2-data" ) ;
+ var key = (vo_type === "vehicles") ? "VEHICLE" : "ORDNANCE" ;
+ params[ key + "_NAME" ] = data.vo_entry.name ;
+ params[ key + "_NOTE_URL" ] = data.vo_note_url ;
+ }
+ if ( template_id === "ob_vehicle_note" )
+ set_vo_note( "vehicles" ) ;
+ else if ( template_id === "ob_ordnance_note" )
+ set_vo_note( "ordnance" ) ;
+
+ // generate snippets for multi-applicable vehicle/ordnance notes
+ 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 ) {
+ var ma_note = ma_notes[ keys[i] ] ;
+ params[ param_name ].push(
+ "" +
+ (nat === "italian" && vo_type === "ordnance" && keys[i] === "R" ? "R" : keys[i]) + ":" +
+ " " +
+ (ma_note || "Unavailable.")
+ ) ;
+ }
+ }
+ function get_ma_notes( vo_type, player_no, param_name ) {
+ var nat = params[ "PLAYER_" + player_no ] ;
+ var vo_entries = params[ "OB_" + vo_type.toUpperCase() + "_" + player_no ] ;
+ var result = get_ma_notes_keys( nat, vo_entries, vo_type, null ) ;
+ if ( ! result )
+ return ;
+ // NOTE: If the V/O entries contain landing craft or common vehicles/ordnance, we get:
+ // [ m/a note keys, m/a note keys for the extras, nat ID for the extras, display caption for the extras, unrecognized keys ]
+ // where "extras" = landing craft or common vehicles/ordnance. Otherwise, we get:
+ // [ m/a note keys, null, null, null, unrecognized keys ]
+ add_ma_notes( get_ma_notes_for_nat(nat,vo_type), result[0], param_name, nat, vo_type ) ;
+ if ( result[1] ) {
+ // there are extras, show their multi-applicable notes separately
+ add_ma_notes( get_ma_notes_for_nat(result[2],vo_type), result[1], param_name.replace("_MA_NOTES_","_EXTRA_MA_NOTES_"), result[2], vo_type ) ;
+ if ( result[0] ) {
+ var param_name2 = "OB_" + vo_type.toUpperCase() + "_EXTRA_MA_NOTES_CAPTION_" + player_no ;
+ params[param_name2] = result[3] ;
+ }
+ }
+ }
+ function get_ma_notes_for_nat( nat, vo_type ) {
+ if ( nat === "landing-craft" && nat in gVehicleOrdnanceNotes.vehicles )
+ return gVehicleOrdnanceNotes.vehicles[ nat ][ "multi-applicable" ] ;
+ if ( vo_type in gVehicleOrdnanceNotes && nat in gVehicleOrdnanceNotes[vo_type] )
+ return gVehicleOrdnanceNotes[ vo_type ][ nat ][ "multi-applicable" ] ;
+ return {} ;
+ }
+ get_ma_notes( "vehicles", 1, "OB_VEHICLES_MA_NOTES_1" ) ;
+ get_ma_notes( "ordnance", 1, "OB_ORDNANCE_MA_NOTES_1" ) ;
+ get_ma_notes( "vehicles", 2, "OB_VEHICLES_MA_NOTES_2" ) ;
+ get_ma_notes( "ordnance", 2, "OB_ORDNANCE_MA_NOTES_2" ) ;
+ function set_params( vo_type, player_no ) {
+ 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 ) {
+ var stem = "OB_" + vo_type_uc + "_" + postfixes[i] ;
+ params[ stem ] = params[ stem + "_" + player_no ] ;
+ }
+ }
+ if ( template_id === "ob_vehicles_ma_notes_1" )
+ set_params( "vehicles", 1 ) ;
+ else if ( template_id === "ob_ordnance_ma_notes_1" )
+ set_params( "ordnance", 1 ) ;
+ else if ( template_id === "ob_vehicles_ma_notes_2" )
+ set_params( "vehicles", 2 ) ;
+ else if ( template_id === "ob_ordnance_ma_notes_2" )
+ set_params( "ordnance", 2 ) ;
+
// include the player display names and flags
params.PLAYER_1_NAME = get_nationality_display_name( params.PLAYER_1 ) ;
params.PLAYER_2_NAME = get_nationality_display_name( params.PLAYER_2 ) ;
@@ -105,13 +182,13 @@ function make_snippet( $btn, extra_params, show_date_warnings )
} ) ;
// generate PF parameters
- if ( params.SCENARIO_YEAR < 1944 || (params.SCENARIO_YEAR == 1944 && params.SCENARIO_MONTH < 6) )
+ if ( params.SCENARIO_YEAR < 1944 || (params.SCENARIO_YEAR === 1944 && params.SCENARIO_MONTH < 6) )
params.PF_RANGE = 1 ;
- else if ( params.SCENARIO_YEAR == 1944 )
+ else if ( params.SCENARIO_YEAR === 1944 )
params.PF_RANGE = 2 ;
else
params.PF_RANGE = 3 ;
- if ( params.SCENARIO_YEAR < 1943 || (params.SCENARIO_YEAR == 1943 && params.SCENARIO_MONTH <= 9) ) {
+ if ( params.SCENARIO_YEAR < 1943 || (params.SCENARIO_YEAR === 1943 && params.SCENARIO_MONTH <= 9) ) {
params.PF_CHECK_DRM = "+1" ;
params.PF_CHECK_DR = 2 ;
} else if ( params.SCENARIO_YEAR >= 1945 ) {
@@ -134,7 +211,7 @@ function make_snippet( $btn, extra_params, show_date_warnings )
params.BAZ_BREAKDOWN = 11 ;
params.BAZ_TOKILL = 16 ;
params.BAZ_RANGE = 4 ;
- } else if ( params.SCENARIO_YEAR == 1943 || (params.SCENARIO_YEAR == 1942 && params.SCENARIO_MONTH >= 11) ) {
+ } else if ( params.SCENARIO_YEAR === 1943 || (params.SCENARIO_YEAR === 1942 && params.SCENARIO_MONTH >= 11) ) {
params.BAZ_TYPE = 43 ;
params.BAZ_BREAKDOWN = 10 ;
params.BAZ_TOKILL = 13 ;
@@ -209,6 +286,131 @@ function make_snippet( $btn, extra_params, show_date_warnings )
return snippet ;
}
+function get_vo_note_key( vo_entry )
+{
+ // get the note number for the specified vehicle/ordnance
+ if ( ! vo_entry.note_number )
+ return null ;
+ // nb: there are some note numbers of the form "1.2" :-/
+ var match = vo_entry.note_number.match( new RegExp( "^([0-9.]+)" ) ) ;
+ return match ? match[1] : null ;
+}
+
+function is_known_vo_note_key( vo_type, nat, key )
+{
+ // check if the vehicle/ordnance note key is known to us
+ return vo_type in gVehicleOrdnanceNotes &&
+ nat in gVehicleOrdnanceNotes[ vo_type ] &&
+ key in gVehicleOrdnanceNotes[ vo_type ][ nat ] ;
+}
+
+function get_ma_notes_keys( nat, vo_entries, vo_type )
+{
+ // figure out which multi-applicable notes are being referenced
+ if ( ! vo_entries )
+ return null ;
+ // NOTE: We need to return 2 sets of referenced keys, one for the normal vehicle/ordnance notes
+ // and one for any landing craft/common vehicles, since they share common keys.
+ var keys = [ {}, {} ] ;
+ var unrecognized = [] ;
+ var regexes = [
+ new RegExp( "^([A-Z]{1,2})$" ),
+ new RegExp( "^([A-Z]{1,2})\\u2020" ),
+ new RegExp( "^([a-z])$" ),
+ new RegExp( "^([a-z])\\u2020" ),
+ new RegExp( "^([A-Z][a-z])$" ),
+ new RegExp( "^([A-Za-z])" ),
+ new RegExp( "^([A-Za-z])$" ),
+ ] ;
+ var EXTRA_NOTES_INFO = {
+ "alc/v": [ "allied-minor", "Allied Minor Common Vehicles" ],
+ "alc/o": [ "allied-minor", "Allied Minor Common Ordnance" ],
+ "axc/v": [ "axis-minor", "Axis Minor Common Vehicles" ],
+ "axc/o": [ "axis-minor", "Axis Minor Common Ordnance" ],
+ "sh/v": [ "landing-craft", "Landing Craft" ],
+ } ;
+ var extra_notes_info = [ null, null ] ;
+ var i, j, k ;
+ for ( i=0 ; i < vo_entries.length ; ++i ) {
+ var vo_entry = vo_entries[i] ;
+ if ( ! vo_entry.notes )
+ continue ;
+ for ( j=0 ; j < vo_entry.notes.length ; ++j ) {
+ var rc = false ;
+ for ( k=0 ; k < regexes.length ; ++k ) {
+ var match = vo_entry.notes[j].match( regexes[k] ) ;
+ if ( match ) {
+ var vo_id = vo_entry.id.split( ":", 1 )[0] ;
+ var is_extra = ["allied-minor","axis-minor","landing-craft"].indexOf( nat ) === -1 &&
+ ["alc/v","alc/o","axc/v","axc/o","sh/v"].indexOf( vo_id ) !== -1 ;
+ keys[ is_extra?1:0 ][ match[1] ] = true ;
+ if ( is_extra ) {
+ // NOTE: Only the Americans/British and Japanese have landing craft, while Axis Minor Powers
+ // will never have Allied Minor common vehicles/ordnance (and vice versa), so if we have
+ // extra notes, they should be all of the same type.
+ extra_notes_info = EXTRA_NOTES_INFO[ vo_id ] ;
+ }
+ rc = true ;
+ break ;
+ }
+ }
+ if ( ! rc ) {
+ unrecognized.push( [ vo_entry, vo_entry.notes[j] ] ) ;
+ console.log( "Couldn't recognize multi-applicable note keys for '" + vo_entry.name + "':", vo_entry.notes[j] ) ;
+ }
+ }
+ }
+
+ return [
+ sort_ma_notes_keys( nat, Object.keys(keys[0]) ),
+ sort_ma_notes_keys( nat, Object.keys(keys[1]) ),
+ extra_notes_info[0], extra_notes_info[1],
+ unrecognized
+ ] ;
+}
+
+function sort_ma_notes_keys( nat, keys )
+{
+ // NOTE: I tried sorting the multi-applicable notes on the server side, but it got very messy very quickly
+ // e.g. we get an ordered list of notes, so we can no longer access them via the key; we have references
+ // to notes that may not be defined e.g. because the user hasn't set them up.
+
+ if ( ! keys || keys.length === 0 )
+ return null ;
+
+ function isUpperCase( ch ) { return ch === ch.toUpperCase() ; }
+ function isLowerCase( ch ) { return ch === ch.toLowerCase() ; }
+
+ // FUDGE! The sort rules don't apply for the special mixed-case keys in the Allied Minor ordnance.
+ // NOTE: There are a few other cases that have two-character mixed-case keys :-/
+ function isSpecialKey( key ) { return key.length === 2 && isUpperCase(key[0]) && isLowerCase(key[1]) ; }
+
+ // sort the multi-applicable note keys
+ keys.sort( function( lhs, rhs ) {
+ if ( ! isSpecialKey(lhs) && ! isSpecialKey(rhs) ) {
+ // upper-case sorts lower than lower-case (so that "AA" appears before "a")
+ if ( isUpperCase(lhs[0]) && isLowerCase(rhs[0]) )
+ return -1 ;
+ if ( isLowerCase(lhs[0]) && isUpperCase(rhs[0]) )
+ return +1 ;
+ // shorter strings sort lower (e.g. so that "A" appears before "AA")
+ if ( lhs.length < rhs.length )
+ return -1 ;
+ else if ( lhs.length > rhs.length )
+ return +1 ;
+ }
+ // return the natural sort order (only for strings with the same case and length)
+ if ( lhs < rhs )
+ return -1 ;
+ else if ( lhs > rhs )
+ return +1 ;
+ else
+ return 0 ;
+ } ) ;
+
+ return keys ;
+}
+
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
function unload_snippet_params( unpack_scenario_date, template_id )
@@ -260,6 +462,7 @@ function unload_snippet_params( unpack_scenario_date, template_id )
var vo_image_id = $(this).data( "sortable2-data" ).vo_image_id ;
var obj = {
id: vo_entry.id,
+ seq_id: $(this).data( "sortable2-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,
@@ -330,7 +533,7 @@ function make_capabilities( raw, vo_entry, nat, scenario_theater, scenario_year,
var no_if = "no IF" ;
if ( typeof(vo_entry.no_if) === "string" ) { // nb: only for the French B1-bis :-/
no_if = vo_entry.no_if ;
- if ( no_if.substring(no_if.length-1) == "\u2020" )
+ if ( no_if.substring(no_if.length-1) === "\u2020" )
no_if = "no IF" + no_if.substring(0,no_if.length-1) + "\u2020" ;
else
no_if = "no IF" + no_if + "" ;
@@ -355,9 +558,9 @@ function make_capabilities( raw, vo_entry, nat, scenario_theater, scenario_year,
continue ;
}
// check for LF
- if ( key == "LF" ) {
+ if ( key === "LF" ) {
var caps = $.extend( true, [], vo_entry.capabilities2[key] ) ;
- if ( caps[caps.length-1] == "\u2020" ) {
+ if ( caps[caps.length-1] === "\u2020" ) {
caps.pop() ;
capabilities.push( "LF\u2020" ) ;
} else
@@ -381,7 +584,7 @@ function make_capabilities( raw, vo_entry, nat, scenario_theater, scenario_year,
var cap = _select_capability_by_date( vo_entry.capabilities2[key], nat, scenario_theater, scenario_year, scenario_month ) ;
if ( cap === null )
continue ;
- if ( cap == "" ) {
+ if ( cap === "" ) {
invalid_caps.push( vo_entry.name + ": " + key + ": " + vo_entry.capabilities2[key] ) ;
continue ;
}
@@ -528,7 +731,7 @@ function _check_capability_timestamp( capabilities, timestamp, nat, scenario_the
}
// remove any trailing "+" (FIXME! What does it even mean? Doesn't make sense :-/)
- if ( timestamp.substring( timestamp.length-1 ) == "+" )
+ if ( timestamp.substring( timestamp.length-1 ) === "+" )
timestamp = timestamp.substring( 0, timestamp.length-1 ) ;
// check if there is anything left
@@ -547,7 +750,7 @@ function _check_capability_timestamp( capabilities, timestamp, nat, scenario_the
// check if the capabilitity is available
if ( scenario_year > 1940 + timestamp )
return capabilities[0] ;
- else if ( scenario_year == 1940 + timestamp ) {
+ else if ( scenario_year === 1940 + timestamp ) {
if( !month || scenario_month >= month )
return capabilities[0] ;
}
@@ -623,10 +826,6 @@ function get_template( template_id, fixup )
function edit_template( template_id )
{
// get the specified template
- if ( template_id.substring(0,12) == "ob_ordnance_" )
- template_id = "ob_ordnance" ;
- else if ( template_id.substring(0,12) == "ob_vehicles_" )
- template_id = "ob_vehicles" ;
var template = get_template( template_id, false ) ;
if ( template === null )
return ;
@@ -737,11 +936,25 @@ function do_load_scenario_data( params )
// auto-assign ID's to the OB setup notes and notes
// NOTE: We do this here to handle scenarios that were created before these ID's were implemented.
- auto_assign_ids( params.SCENARIO_NOTES ) ;
- auto_assign_ids( params.OB_SETUPS_1 ) ;
- auto_assign_ids( params.OB_NOTES_1 ) ;
- auto_assign_ids( params.OB_SETUPS_2 ) ;
- auto_assign_ids( params.OB_NOTES_2 ) ;
+ auto_assign_ids( params.SCENARIO_NOTES, "id" ) ;
+ auto_assign_ids( params.OB_SETUPS_1, "id" ) ;
+ auto_assign_ids( params.OB_NOTES_1, "id" ) ;
+ auto_assign_ids( params.OB_VEHICLES_1, "seq_id" ) ;
+ auto_assign_ids( params.OB_ORDNANCE_1, "seq_id" ) ;
+ auto_assign_ids( params.OB_SETUPS_2, "id" ) ;
+ auto_assign_ids( params.OB_NOTES_2, "id" ) ;
+ auto_assign_ids( params.OB_VEHICLES_2, "seq_id" ) ;
+ auto_assign_ids( params.OB_ORDNANCE_2, "seq_id" ) ;
+
+ // set default values
+ function set_default_val( key, val ) {
+ if ( ! (key in params) )
+ params[key] = val ;
+ }
+ set_default_val( "OB_VEHICLES_MA_NOTES_WIDTH_1", "300px" ) ;
+ set_default_val( "OB_ORDNANCE_MA_NOTES_WIDTH_1", "300px" ) ;
+ set_default_val( "OB_VEHICLES_MA_NOTES_WIDTH_2", "300px" ) ;
+ set_default_val( "OB_ORDNANCE_MA_NOTES_WIDTH_2", "300px" ) ;
// load the scenario parameters
var params_loaded = {} ;
@@ -830,7 +1043,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 ) ;
+ do_add_vo( vo_type, player_no, vo_entry, vo_image_id, params[key][i].custom_capabilities, params[key][i].seq_id ) ;
else
unknown_vo.push( vo_id || "(not set)" ) ;
}
@@ -871,7 +1084,7 @@ function do_load_scenario_data( params )
}
// show any other warnings
- if ( warnings.length == 1 )
+ if ( warnings.length === 1 )
showWarningMsg( warnings[0] ) ;
else if ( warnings.length > 1 ) {
showWarningMsg( makeBulletListMsg(
@@ -890,7 +1103,7 @@ function do_load_scenario_data( params )
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-function auto_assign_ids( vals )
+function auto_assign_ids( vals, key )
{
if ( ! vals )
return ;
@@ -910,14 +1123,14 @@ function auto_assign_ids( vals )
// identify which ID's are currently in use
var usedIds = {} ;
for ( var i=0 ; i < vals.length ; ++i ) {
- if ( vals[i].id )
- usedIds[ vals[i].id ] = true ;
+ if ( vals[i][key] )
+ usedIds[ vals[i][key] ] = true ;
}
// assign ID's to entries that don't have one
for ( i=0 ; i < vals.length ; ++i ) {
- if ( ! vals[i].id )
- vals[i].id = auto_assign_id( usedIds ) ;
+ if ( ! vals[i][key] )
+ vals[i][key] = auto_assign_id( usedIds ) ;
}
}
@@ -976,12 +1189,13 @@ function on_save_scenario()
function unload_params_for_save( user_requested )
{
function extract_vo_entries( key ) {
- if ( !(key in params) )
+ if ( !( key in params ) )
return ;
var entries = [] ;
for ( var i=0 ; i < params[key].length ; ++i ) {
var entry = {
id: params[key][i].id,
+ seq_id: params[key][i].seq_id,
name: params[key][i].name, // nb: not necessary, but convenient
} ;
if ( params[key][i].image_id !== null )
@@ -1123,7 +1337,7 @@ function on_template_pack()
var pos = data.indexOf( "|" ) ;
var fname = data.substring( 0, pos ).trim() ;
data = data.substring( pos+1 ).trim() ;
- if ( fname.substring(fname.length-4) == ".zip" )
+ if ( fname.substring(fname.length-4) === ".zip" )
data = atob( data ) ;
do_load_template_pack( fname, data ) ;
return ;
@@ -1244,7 +1458,7 @@ function do_load_template_pack( fname, data )
// check if we have a ZIP file
fname = fname.toLowerCase() ;
- if ( fname.substring(fname.length-4) == ".zip" ) {
+ if ( fname.substring(fname.length-4) === ".zip" ) {
// yup - process each file in the ZIP
var nFiles = 0 ;
JSZip.loadAsync( data ).then( function( zip ) {
diff --git a/vasl_templates/webapp/static/vassal.js b/vasl_templates/webapp/static/vassal.js
index 253d167..18aa32e 100644
--- a/vasl_templates/webapp/static/vassal.js
+++ b/vasl_templates/webapp/static/vassal.js
@@ -180,30 +180,37 @@ function _generate_snippets()
// the snippet, which is more trouble than it's worth, at this point.
return ;
}
+ 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 data ;
if ( ["scenario_note","ob_setup","ob_note"].indexOf( template_id ) !== -1 ) {
- var data = $btn.parent().parent().data( "sortable2-data" ) ;
+ data = $btn.parent().parent().data( "sortable2-data" ) ;
if ( player_no )
snippet_id = template_id + "_" + player_no + "." + data.id ;
else
snippet_id = template_id + "." + data.id ;
extra_params = get_simple_note_snippet_extra_params( $btn ) ;
}
- var raw_content = _get_raw_content( snippet_id, $btn ) ;
+ if ( ["ob_vehicle_note","ob_ordnance_note"].indexOf( template_id ) !== -1 ) {
+ data = $btn.parent().parent().data( "sortable2-data" ) ;
+ snippet_id = template_id + "_" + player_no + "." + data.id ;
+ }
+ var raw_content = _get_raw_content( snippet_id, $btn, params ) ;
if ( ["scenario","players","victory_conditions"].indexOf( snippet_id ) === -1 ) {
// NOTE: We don't pass through a snippet for things that have no content,
// except for important stuff, such as the scenario name and victory conditions.
- if ( raw_content === null || raw_content.length === 0 ) {
+ if ( raw_content === false || raw_content === null || raw_content.length === 0 ) {
return ;
}
}
snippets[snippet_id] = {
- content: make_snippet( $btn, extra_params, false ),
+ content: make_snippet( $btn, params, extra_params, false ),
auto_create: ! no_autocreate[template_id] && ! inactive,
- raw_content: raw_content,
} ;
+ if ( raw_content !== true )
+ snippets[snippet_id].raw_content = raw_content ;
if ( player_no )
snippets[snippet_id].label_area = "player" + player_no ;
}
@@ -219,7 +226,7 @@ function _generate_snippets()
return snippets ;
}
-function _get_raw_content( snippet_id, $btn )
+function _get_raw_content( snippet_id, $btn, params )
{
// NOTE: We pass the raw content, as entered by the user into the UI, through to the VASSAL shim,
// so that it can locate legacy labels, that were created before we added snippet ID's to the templates.
@@ -270,21 +277,56 @@ function _get_raw_content( snippet_id, $btn )
if ( snippet_id === "baz" )
return [ "Bazooka", "Range", "TH#" ] ;
+ // handle vehicle/ordnance notes
+ // NOTE: These were implemented after we added snippet ID's, so there's no need to support legacy labels.
+ // NOTE: We get called in response to an img.snippet button, which implies there is a Chapter H snippet available,
+ // so we don't have to check anything and just always return true.
+ if ( snippet_id.substring(0,16) === "ob_vehicle_note_" )
+ return true ;
+ if ( snippet_id.substring(0,17) === "ob_ordnance_note_" )
+ return true ;
+
// handle simple notes
if ( $btn.prop( "tagName" ).toLowerCase() == "img" ) {
var data = $btn.parent().parent().data( "sortable2-data" ) ;
return [ data.caption ] ;
}
- // handle vehicles/ordnance
- if ( snippet_id.substring(0,11) === "ob_vehicles" || snippet_id.substring(0,11) === "ob_ordnance" ) {
- var id = snippet_id.substring(0,11) + "-sortable" + snippet_id.substring(11) ;
+ function get_vo_entries( vo_type, player_no, names_only ) {
+ var vo_entries = [] ;
+ var id = "ob_" + vo_type + "-sortable_" + player_no ;
$( "#"+id + " > li" ).each( function() {
var vo_entry = $(this).data( "sortable2-data" ).vo_entry ;
- raw_content.push( vo_entry.name ) ;
+ vo_entries.push( names_only ? vo_entry.name : vo_entry ) ;
} ) ;
- return raw_content ;
+ return vo_entries ;
}
+ // handle multi-applicable vehicle/ordnance notes
+ // NOTE: These were implemented after we added snippet ID's, so there's no need to support legacy labels.
+ function check_ma_notes( vo_type, player_no ) {
+ var nat = params[ "PLAYER_" + player_no ] ;
+ // NOTE: The following test has to handle a number of subtleties:
+ // - if no Chapter H data has been configured, we don't create the label
+ // However, if Chapter data has been configured, we always create the label, even if:
+ // - there are no notes whatsoever (e.g. Romania).
+ // - there are notes, but no multi-applicable notes (e.g. Belgium)
+ // It's tempting to think that it might be better to skip creating the label if there are no available
+ // multi-applicable notes, but this will be confusing for the user, since the label will not appear
+ // in the VASL scenario, and it won't be immediately clear why.
+ if ( !( vo_type in gVehicleOrdnanceNotes && Object.keys(gVehicleOrdnanceNotes[vo_type]).length > 0 ) )
+ return false ;
+ vo_entries = get_vo_entries( vo_type, player_no, false ) ;
+ var result = get_ma_notes_keys( nat, vo_entries, vo_type ) ;
+ return (result[0] && result[0].length > 0) || (result[1] && result[1].length > 0) ;
+ }
+ var player_no, nat, vo_entries, keys ;
+ if ( snippet_id.substring(0,21) === "ob_vehicles_ma_notes_" || snippet_id.substring(0,21) === "ob_ordnance_ma_notes_" )
+ return check_ma_notes( snippet_id.substring(3,11), snippet_id.substring(21) ) ;
+
+ // handle vehicles/ordnance
+ if ( snippet_id.substring(0,12) === "ob_vehicles_" || snippet_id.substring(0,12) === "ob_ordnance_" )
+ return get_vo_entries( snippet_id.substring(3,11), snippet_id.substring(12), true ) ;
+
return null ;
}
diff --git a/vasl_templates/webapp/static/vo.js b/vasl_templates/webapp/static/vo.js
index 97a8eb0..977c2a2 100644
--- a/vasl_templates/webapp/static/vo.js
+++ b/vasl_templates/webapp/static/vo.js
@@ -112,7 +112,12 @@ function add_vo( vo_type, player_no )
var sel_index = $elem.children( ".vo-entry" ).data( "index" ) ;
var $img = $elem.find( "img[class='vasl-image']" ) ;
var vo_image_id = $img.data( "vo-image-id" ) ;
- do_add_vo( vo_type, player_no, entries[sel_index], vo_image_id, null ) ;
+ var usedIds = {};
+ $sortable2.find( "li" ).each( function() {
+ usedIds[ $(this).data( "sortable2-data" ).id ] = true ;
+ } ) ;
+ var seq_id = auto_assign_id( usedIds, "seq_id" ) ;
+ do_add_vo( vo_type, player_no, entries[sel_index], vo_image_id, null, seq_id ) ;
$(this).dialog( "close" ) ;
},
Cancel: function() { $(this).dialog( "close" ) ; },
@@ -122,11 +127,12 @@ function add_vo( vo_type, player_no )
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-function do_add_vo( vo_type, player_no, vo_entry, vo_image_id, custom_capabilities )
+function do_add_vo( vo_type, player_no, vo_entry, vo_image_id, custom_capabilities, 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),
// so that the vehicle/ordnance images won't get truncated if there are a lot of them.
+ var nat = get_player_nat( player_no ) ;
var $sortable2 = $( "#ob_" + vo_type + "-sortable_" + player_no ) ;
var div_tag = "" ] ;
+ ""
+ ] ;
+ var vo_note_key = get_vo_note_key( vo_entry ) ;
+ var vo_nat ;
+ if ( is_known_vo_note_key( vo_type, nat, vo_note_key ) )
+ vo_nat = nat ;
+ else {
+ // NOTE: Note numbers seem to be distinct across all Allied Minor or all Axis Minor vehicles/ordnance,
+ // so if we don't find a note in a given nationality's normal vehicles/ordnance, we can get away with
+ // just checking their corresponding common vehicles/ordnance.
+ var nat_type = gTemplatePack.nationalities[ nat ].type ;
+ if ( ["allied-minor","axis-minor"].indexOf( nat_type ) !== -1 ) {
+ if ( is_known_vo_note_key( vo_type, nat_type, vo_note_key ) )
+ vo_nat = nat_type ;
+ }
+ }
+ if ( vo_nat ) {
+ var template_id = (vo_type === "vehicles") ? "ob_vehicle_note" : "ob_ordnance_note" ;
+ buf.push(
+ ""
+ ) ;
+ data.vo_note_url = APP_URL_BASE + "/" + vo_type + "/" + vo_nat + "/note/" + vo_note_key ;
+ }
+ buf.push( "" ) ;
+ var $content = $( buf.join("") ) ;
var $entry = $sortable2.sortable2( "add", {
- content: $( buf.join("") ),
+ content: $content,
data: data,
} ) ;
update_vo_sortable2_entry( $entry ) ;
+
+ // add a handler for the snippet button
+ $content.children("img.snippet").click( function() {
+ generate_snippet( $(this), {} ) ;
+ } ) ;
}
function update_vo_sortable2_entry( $entry, snippet_params )
diff --git a/vasl_templates/webapp/templates/index.html b/vasl_templates/webapp/templates/index.html
index 092290e..4f5a6a1 100644
--- a/vasl_templates/webapp/templates/index.html
+++ b/vasl_templates/webapp/templates/index.html
@@ -94,6 +94,8 @@ gGetTemplatePackUrl = "{{url_for('get_template_pack')}}" ;
gGetDefaultScenarioUrl = "{{url_for('get_default_scenario')}}" ;
gVehicleListingsUrl = "{{url_for('get_vehicle_listings',merge_common=1)}}" ;
gOrdnanceListingsUrl = "{{url_for('get_ordnance_listings',merge_common=1)}}" ;
+gVehicleNotesUrl = "{{url_for('get_vehicle_notes')}}" ;
+gOrdnanceNotesUrl = "{{url_for('get_ordnance_notes')}}" ;
gGetVaslPieceInfoUrl = "{{url_for('get_vasl_piece_info')}}" ;
gUpdateVsavUrl = "{{url_for('update_vsav')}}" ;
gHelpUrl = "{{url_for('show_help')}}" ;
diff --git a/vasl_templates/webapp/templates/tabs-ob1.html b/vasl_templates/webapp/templates/tabs-ob1.html
index 5bb6a92..3b9093f 100644
--- a/vasl_templates/webapp/templates/tabs-ob1.html
+++ b/vasl_templates/webapp/templates/tabs-ob1.html
@@ -52,13 +52,24 @@
@@ -71,13 +82,24 @@
diff --git a/vasl_templates/webapp/templates/vo-notes-report.html b/vasl_templates/webapp/templates/vo-notes-report.html
new file mode 100644
index 0000000..a428bbc
--- /dev/null
+++ b/vasl_templates/webapp/templates/vo-notes-report.html
@@ -0,0 +1,182 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/vasl_templates/webapp/templates/vo-report.html b/vasl_templates/webapp/templates/vo-report.html
index df9749b..c2d39f2 100644
--- a/vasl_templates/webapp/templates/vo-report.html
+++ b/vasl_templates/webapp/templates/vo-report.html
@@ -22,7 +22,7 @@ td { padding: 0.2em 0.5em ; }