diff --git a/vasl_templates/main_window.py b/vasl_templates/main_window.py
index 63ba574..5cb4e68 100644
--- a/vasl_templates/main_window.py
+++ b/vasl_templates/main_window.py
@@ -28,7 +28,8 @@ class AppWebPage( QWebEnginePage ):
def acceptNavigationRequest( self, url, nav_type, is_mainframe ): #pylint: disable=no-self-use,unused-argument
"""Called when a link is clicked."""
if url.host() in ("localhost","127.0.0.1"):
- return True
+ if "/asl-rulebook2/" not in url.url(): # nb: asl-rulebook2 links are routed through our webapp
+ return True
if not is_mainframe:
# NOTE: We get here if we're in a child frame (e.g. Google Maps). However, we can't just ignore
# these requests, because the help is also in a frame, and we want links to open in an external browser.
diff --git a/vasl_templates/webapp/__init__.py b/vasl_templates/webapp/__init__.py
index 048347e..eb3b961 100644
--- a/vasl_templates/webapp/__init__.py
+++ b/vasl_templates/webapp/__init__.py
@@ -52,6 +52,9 @@ def _init_webapp():
# NOTE: While this is generally called only once (before the first request), the test suite
# can force it be done again, since it wants to reconfigure the server to test different cases.
+ # initialize
+ from vasl_templates.webapp.main import startup_msg_store #pylint: disable=cyclic-import
+
# start downloading files
# NOTE: We used to do this in the mainline code of __init__, so that we didn't have to wait
# for the first request before starting the download (useful if we are running as a standalone server).
@@ -71,7 +74,6 @@ def _init_webapp():
# configure the VASL module
fname = app.config.get( "VASL_MOD" )
from vasl_templates.webapp.vasl_mod import set_vasl_mod #pylint: disable=cyclic-import
- from vasl_templates.webapp.main import startup_msg_store #pylint: disable=cyclic-import
set_vasl_mod( fname, startup_msg_store )
# load the vehicle/ordnance listings
@@ -82,6 +84,10 @@ def _init_webapp():
from vasl_templates.webapp.vo_notes import load_vo_notes #pylint: disable=cyclic-import
load_vo_notes( startup_msg_store )
+ # load integration data from asl-rulebook2
+ from vasl_templates.webapp.vo_notes import load_asl_rulebook2_vo_note_targets #pylint: disable=cyclic-import
+ load_asl_rulebook2_vo_note_targets( startup_msg_store )
+
# ---------------------------------------------------------------------
def _load_config( fname, section ):
diff --git a/vasl_templates/webapp/static/css/sortable.css b/vasl_templates/webapp/static/css/sortable.css
index be33d30..bf06f9a 100644
--- a/vasl_templates/webapp/static/css/sortable.css
+++ b/vasl_templates/webapp/static/css/sortable.css
@@ -9,6 +9,7 @@ img.sortable-reset { vertical-align: middle ; height: 15px ; margin-right: 0.25e
.sortable li:hover { cursor: pointer ; }
.sortable li.ui-sortable-helper { opacity: 0.8 ; }
.sortable li img.snippet { height: 1.25em ; margin: -2px -2px ; padding-left: 1em ; float: right ; }
+.sortable li img.aslrb2 { height: 1.25em ; position: absolute ; bottom: -2px ; right: -2px ; opacity: 0.6 ; }
.sortable ul li, .sortable ol li { margin-top: -0.75em ; } /* nb: tighten up lists in sortable2 entries */
diff --git a/vasl_templates/webapp/static/css/tabs-ob.css b/vasl_templates/webapp/static/css/tabs-ob.css
index b5005e2..3415c94 100644
--- a/vasl_templates/webapp/static/css/tabs-ob.css
+++ b/vasl_templates/webapp/static/css/tabs-ob.css
@@ -21,7 +21,7 @@
.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 ; }
+.panel-ob_vo .sortable .vo-entry { display: flex ; position: relative ; }
.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 ; }
diff --git a/vasl_templates/webapp/static/images/aslrb2.png b/vasl_templates/webapp/static/images/aslrb2.png
new file mode 100644
index 0000000..a63f3c7
Binary files /dev/null and b/vasl_templates/webapp/static/images/aslrb2.png differ
diff --git a/vasl_templates/webapp/static/main.js b/vasl_templates/webapp/static/main.js
index af5c089..d09cf33 100644
--- a/vasl_templates/webapp/static/main.js
+++ b/vasl_templates/webapp/static/main.js
@@ -6,6 +6,7 @@ gVehicleOrdnanceListings = {} ;
gVehicleOrdnanceNotes = {} ;
gVaslPieceInfo = {} ;
gOnlineCounterImages = {} ;
+gAslRulebook2VoNoteTargets = {} ;
gWebChannelHandler = null ;
gEmSize = null ;
@@ -347,6 +348,16 @@ $(document).ready( function () {
update_page_load_status( "template-pack" ) ;
} ) ;
+ // get the ASL Rulebook2 vehicle/ordnance note targets
+ $.getJSON( gGetAslRulebook2VoNoteTargetsUrl, function(data) {
+ gAslRulebook2VoNoteTargets = data ;
+ update_page_load_status( "asl-rulebook2-vo-note-targets" ) ;
+ } ).fail( function( xhr, status, errorMsg ) {
+ if ( xhr.status != 404 )
+ showErrorMsg( "Can't get the ASL Rulebook2 vehicle/ordnance note targets:
" + escapeHTML(errorMsg) + "
" ) ;
+ update_page_load_status( "asl-rulebook2-vo-note-targets" ) ;
+ } ) ;
+
// fixup the layout
var prevHeight = [] ;
$(window).resize( function() {
@@ -534,7 +545,7 @@ function init_snippet_button( $btn )
gPageLoadStatus = [
"main", "app-config",
"vehicle-listings", "ordnance-listings", "reset-scenario",
- "vehicle-notes", "ordnance-notes",
+ "vehicle-notes", "ordnance-notes", "asl-rulebook2-vo-note-targets",
"vasl-piece-info", "online-counter-images", "template-pack", "default-scenario"
] ;
diff --git a/vasl_templates/webapp/static/utils.js b/vasl_templates/webapp/static/utils.js
index 43beec2..bf0ae7e 100644
--- a/vasl_templates/webapp/static/utils.js
+++ b/vasl_templates/webapp/static/utils.js
@@ -459,7 +459,7 @@ function get_month_name( month )
// --------------------------------------------------------------------
-function fixup_external_links( $root )
+function fixup_external_links( $root, fixAll )
{
// NOTE: We want to open externals links in a new browser window, but simply adding target="_blank"
// breaks the desktop app's ability to intercept clicks (in AppWebPage.acceptNavigationRequest()),
@@ -467,7 +467,7 @@ function fixup_external_links( $root )
var regex = new RegExp( "^https?://" ) ;
$root.find( "a" ).each( function() {
var url = $(this).attr( "href" ) ;
- if ( url && url.match( regex ) )
+ if ( fixAll || ( url && url.match( regex ) ) )
$(this).attr( "target", gWebChannelHandler?"":"_blank" ) ;
} ) ;
}
diff --git a/vasl_templates/webapp/static/vo.js b/vasl_templates/webapp/static/vo.js
index 72976b7..97ae1aa 100644
--- a/vasl_templates/webapp/static/vo.js
+++ b/vasl_templates/webapp/static/vo.js
@@ -155,6 +155,9 @@ function do_add_vo( vo_type, player_no, vo_entry, vo_image_id, elite, custom_cap
{
// initialize
var nat = get_player_nat( player_no ) ;
+ var nat_type = gTemplatePack.nationalities[ nat ].type ;
+ var vo_note_key = get_vo_note_key( vo_entry ) ;
+ var is_landing_craft = vo_note_key ? vo_note_key.substring( 0, 3 ) === "LC " : null ;
var $sortable2 = $( "#ob_" + vo_type + "-sortable_" + player_no ) ;
if ( seq_id === null ) {
// auto-assign a sequence ID
@@ -165,6 +168,43 @@ function do_add_vo( vo_type, player_no, vo_entry, vo_image_id, elite, custom_cap
seq_id = auto_assign_id( usedSeqIds, "seq_id" ) ;
}
+ // check if an asl-rulebook2 Chapter H note is available
+ var aslrb2_url = null ;
+ var aslrb2_nat = nat ;
+ if ( [ "allied-minor", "axis-minor" ].indexOf( nat_type ) != -1 )
+ aslrb2_nat = nat_type ;
+ else {
+ var pos = aslrb2_nat.indexOf( "~" ) ;
+ if ( pos > 0 ) {
+ // NOTE: This is a derived nationality - use the base nationality.
+ aslrb2_nat = aslrb2_nat.substring( 0, pos ) ;
+ } else {
+ // check for K:FW vehicles/ordnance
+ pos = vo_entry.id.indexOf( "/" ) ;
+ if ( pos > 0 ) {
+ var nat2 = vo_entry.id.substring( 0, pos ) ;
+ if ( nat2 == "kfw-uro" || nat2 == "kfw-bcfk" || nat2 == "kfw-un-common")
+ aslrb2_nat = "un-forces" ;
+ else if ( nat2 == "kfw-kpa" || nat2 == "kfw-cpva" )
+ aslrb2_nat = "communist-forces" ;
+ }
+ }
+ }
+ var entries = is_landing_craft ? gAslRulebook2VoNoteTargets["landing-craft"] : gAslRulebook2VoNoteTargets[aslrb2_nat] && gAslRulebook2VoNoteTargets[aslrb2_nat][vo_type] ;
+ if ( entries ) {
+ var key = vo_note_key ;
+ if ( is_landing_craft )
+ key = vo_note_key.substring( 3 ) ;
+ else {
+ var match = key.match( /^kfw-(un|un-common|comm):/ ) ;
+ if ( match )
+ key = key.substring( match[0].length ) ;
+ }
+ var aslrb2_entry = entries[ key ] ;
+ if ( aslrb2_entry )
+ aslrb2_url = gShowAslRulebook2VoNoteUrl.replace( "TARGET", aslrb2_entry.target ) ;
+ }
+
// 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.
@@ -194,11 +234,10 @@ function do_add_vo( vo_type, player_no, vo_entry, vo_image_id, elite, custom_cap
"",
""
] ;
- var vo_note_key = get_vo_note_key( vo_entry ) ;
var vo_note = get_vo_note( vo_type, nat, vo_note_key ) ;
var vo_note_image_url = null ;
if ( vo_note ) {
- if ( vo_note_key.substring( 0, 3 ) === "LC " )
+ if ( is_landing_craft )
vo_note_image_url = make_app_url( "/" + vo_type + "/landing-craft/note/" + vo_note_key.substring(3), true ) ;
else
vo_note_image_url = make_app_url( "/" + vo_type + "/" + nat + "/note/" + vo_note_key, true ) ;
@@ -206,7 +245,6 @@ function do_add_vo( vo_type, player_no, vo_entry, vo_image_id, elite, custom_cap
// 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 ) {
vo_note = get_vo_note( vo_type, nat_type, vo_note_key ) ;
if ( vo_note )
@@ -224,8 +262,16 @@ function do_add_vo( vo_type, player_no, vo_entry, vo_image_id, elite, custom_cap
data.vo_note = vo_note ;
data.vo_note_image_url = vo_note_image_url ;
}
+ if ( aslrb2_url ) {
+ buf.push(
+ "",
+ "",
+ ""
+ ) ;
+ }
buf.push( "" ) ;
var $content = $( buf.join("") ) ;
+ fixup_external_links( $content, true ) ;
var $entry = $sortable2.sortable2( "add", {
content: $content,
data: data,
diff --git a/vasl_templates/webapp/templates/index.html b/vasl_templates/webapp/templates/index.html
index d0077e8..f194019 100644
--- a/vasl_templates/webapp/templates/index.html
+++ b/vasl_templates/webapp/templates/index.html
@@ -126,6 +126,8 @@ gImagesBaseUrl = "{{url_for('static',filename='images')}}" ;
gAppConfigUrl = "{{url_for('get_app_config')}}" ;
gGetStartupMsgsUrl = "{{url_for('get_startup_msgs')}}" ;
gGetTemplatePackUrl = "{{url_for('get_template_pack')}}" ;
+gGetAslRulebook2VoNoteTargetsUrl = "{{url_for('get_asl_rulebook2_vo_note_targets')}}" ;
+gShowAslRulebook2VoNoteUrl = "{{url_for('show_asl_rulebook2_target',target='TARGET')}}" ;
gGetDefaultScenarioUrl = "{{url_for('get_default_scenario')}}" ;
gVehicleListingsUrl = "{{url_for('get_vehicle_listings',merge_common=1)}}" ;
gOrdnanceListingsUrl = "{{url_for('get_ordnance_listings',merge_common=1)}}" ;
diff --git a/vasl_templates/webapp/tests/control_tests_servicer.py b/vasl_templates/webapp/tests/control_tests_servicer.py
index bb99c2c..bf98921 100644
--- a/vasl_templates/webapp/tests/control_tests_servicer.py
+++ b/vasl_templates/webapp/tests/control_tests_servicer.py
@@ -156,6 +156,7 @@ class ControlTestsServicer( BaseControlTestsServicer ): #pylint: disable=too-man
self.setAppConfigVal( SetAppConfigValRequest( key="DISABLE_DOWNLOADED_FILES", boolVal=True ), ctx )
self.setAppConfigVal( SetAppConfigValRequest( key="DISABLE_LOCAL_ASA_INDEX_UPDATES", boolVal=True ), ctx )
self.setAppConfigVal( SetAppConfigValRequest( key="DISABLE_LFA_HOTNESS_FADEIN", boolVal=True ), ctx )
+ self.deleteAppConfigVal( DeleteAppConfigValRequest( key="ASL_RULEBOOK2_BASE_URL" ), ctx )
self.deleteAppConfigVal( DeleteAppConfigValRequest( key="ALTERNATE_WEBAPP_BASE_URL" ), ctx )
# NOTE: The webapp has been reconfigured, but the client must reloaed the home page
# with "?force-reinit=1", to force it to re-initialize with the new settings.
diff --git a/vasl_templates/webapp/tests/fixtures/asl-rulebook2/vo-note-targets.json b/vasl_templates/webapp/tests/fixtures/asl-rulebook2/vo-note-targets.json
new file mode 100644
index 0000000..776654f
--- /dev/null
+++ b/vasl_templates/webapp/tests/fixtures/asl-rulebook2/vo-note-targets.json
@@ -0,0 +1,60 @@
+{
+
+"german": {
+"vehicles": {
+ "1": { "caption": "german/vehicles #1", "target": "gv:1" }
+}
+},
+
+"russian": {
+"ordnance": {
+ "2": { "caption": "russian/ordnance #2", "target": "ro:2" }
+}
+},
+
+"allied-minor": {
+"vehicles": {
+ "1": { "caption": "dutch/vehicles #1", "target": "dv:1" },
+ "101": { "caption": "allied-minor/vehicles #101", "target": "almv:101" }
+}
+},
+
+"axis-minor": {
+"ordnance": {
+ "4": { "caption": "romanian/ordnance #4", "target": "ro:4" },
+ "104": { "caption": "axis-minor/ordnance #104", "target": "axmo:104" }
+}
+},
+
+"landing-craft": {
+ "1": { "caption": "landing-craft #1", "target": "lc:1" },
+ "2": { "caption": "landing-craft #2", "target": "lc:2" }
+},
+
+"chinese": {
+"vehicles": {
+ "1": { "caption": "chinese/vehicles #1", "target": "chv:1" }
+}
+},
+
+"un-forces": {
+"vehicles": {
+ "5": { "caption": "un-forces/vehicles #5", "target": "kfw-un:5" },
+ "6": { "caption": "un-forces/vehicles #6", "target": "kfw-un:6" }
+},
+"ordnance": {
+ "7": { "caption": "un-forces/ordnance #7", "target": "kfw-un:7" },
+ "8": { "caption": "un-forces/ordnance #8", "target": "kfw-un:8" }
+}
+},
+
+"communist-forces": {
+"vehicles": {
+ "15": { "caption": "communist-forces/vehicles #15", "target": "kfw-comm:15" }
+},
+"ordnance": {
+ "16": { "caption": "communist-forces/ordnance #16", "target": "kfw-comm:16" }
+}
+}
+
+}
diff --git a/vasl_templates/webapp/tests/fixtures/data/default-template-pack/nationalities.json b/vasl_templates/webapp/tests/fixtures/data/default-template-pack/nationalities.json
index fa5755d..0bb40ee 100644
--- a/vasl_templates/webapp/tests/fixtures/data/default-template-pack/nationalities.json
+++ b/vasl_templates/webapp/tests/fixtures/data/default-template-pack/nationalities.json
@@ -81,6 +81,10 @@
"type": "axis-minor"
},
+"kfw-kpa": {
+ "display_name": "North Korean",
+ "ob_colors": [ "OBCOL:kfw-kpa","OBCOL2:kfw-kpa", "OBCOL-BORDER:kfw-kpa" ]
+},
"kfw-cpva": {
"display_name": "Communist Chinese",
"ob_colors": [ "OBCOL:kfw-cpva","OBCOL2:kfw-cpva", "OBCOL-BORDER:kfw-cpva" ]
diff --git a/vasl_templates/webapp/tests/fixtures/data/ordnance/british.json b/vasl_templates/webapp/tests/fixtures/data/ordnance/british.json
new file mode 100644
index 0000000..fe51488
--- /dev/null
+++ b/vasl_templates/webapp/tests/fixtures/data/ordnance/british.json
@@ -0,0 +1 @@
+[]
diff --git a/vasl_templates/webapp/tests/fixtures/data/ordnance/kfw-cpva.json b/vasl_templates/webapp/tests/fixtures/data/ordnance/kfw-cpva.json
new file mode 100644
index 0000000..fe51488
--- /dev/null
+++ b/vasl_templates/webapp/tests/fixtures/data/ordnance/kfw-cpva.json
@@ -0,0 +1 @@
+[]
diff --git a/vasl_templates/webapp/tests/fixtures/data/ordnance/kfw/bcfk.json b/vasl_templates/webapp/tests/fixtures/data/ordnance/kfw/bcfk.json
new file mode 100644
index 0000000..74e3437
--- /dev/null
+++ b/vasl_templates/webapp/tests/fixtures/data/ordnance/kfw/bcfk.json
@@ -0,0 +1,8 @@
+[
+
+{ "name": "kfw british ordnance",
+ "note_number": "7",
+ "id": "kfw-bcfk/o:7"
+}
+
+]
diff --git a/vasl_templates/webapp/tests/fixtures/data/ordnance/kfw/cpva.json b/vasl_templates/webapp/tests/fixtures/data/ordnance/kfw/cpva.json
new file mode 100644
index 0000000..8fe48d0
--- /dev/null
+++ b/vasl_templates/webapp/tests/fixtures/data/ordnance/kfw/cpva.json
@@ -0,0 +1,8 @@
+[
+
+{ "name": "cpva ordnance",
+ "note_number": "16",
+ "id": "kfw-cpva/o:016"
+}
+
+]
diff --git a/vasl_templates/webapp/tests/fixtures/data/ordnance/kfw/un-common.json b/vasl_templates/webapp/tests/fixtures/data/ordnance/kfw/un-common.json
new file mode 100644
index 0000000..05d9961
--- /dev/null
+++ b/vasl_templates/webapp/tests/fixtures/data/ordnance/kfw/un-common.json
@@ -0,0 +1,8 @@
+[
+
+{ "name": "kfw common ordnance",
+ "note_number": "8\u2020",
+ "id": "kfw-un-common/o:008"
+}
+
+]
diff --git a/vasl_templates/webapp/tests/fixtures/data/vehicles/kfw-kpa.json b/vasl_templates/webapp/tests/fixtures/data/vehicles/kfw-kpa.json
new file mode 100644
index 0000000..fe51488
--- /dev/null
+++ b/vasl_templates/webapp/tests/fixtures/data/vehicles/kfw-kpa.json
@@ -0,0 +1 @@
+[]
diff --git a/vasl_templates/webapp/tests/fixtures/data/vehicles/kfw/kpa.json b/vasl_templates/webapp/tests/fixtures/data/vehicles/kfw/kpa.json
new file mode 100644
index 0000000..d7d9b6c
--- /dev/null
+++ b/vasl_templates/webapp/tests/fixtures/data/vehicles/kfw/kpa.json
@@ -0,0 +1,8 @@
+[
+
+{ "name": "kpa vehicle",
+ "note_number": "15",
+ "id": "kfw-kpa/v:015"
+}
+
+]
diff --git a/vasl_templates/webapp/tests/fixtures/data/vehicles/kfw/un-common.json b/vasl_templates/webapp/tests/fixtures/data/vehicles/kfw/un-common.json
new file mode 100644
index 0000000..1818d9f
--- /dev/null
+++ b/vasl_templates/webapp/tests/fixtures/data/vehicles/kfw/un-common.json
@@ -0,0 +1,8 @@
+[
+
+{ "name": "kfw common vehicle",
+ "note_number": "6\u2020",
+ "id": "kfw-un-common/v:006"
+}
+
+]
diff --git a/vasl_templates/webapp/tests/fixtures/data/vehicles/kfw/us-rok-ounc.json b/vasl_templates/webapp/tests/fixtures/data/vehicles/kfw/us-rok-ounc.json
new file mode 100644
index 0000000..8fd1779
--- /dev/null
+++ b/vasl_templates/webapp/tests/fixtures/data/vehicles/kfw/us-rok-ounc.json
@@ -0,0 +1,8 @@
+[
+
+{ "name": "kfw us vehicle",
+ "note_number": "5",
+ "id": "kfw-uro/v:005"
+}
+
+]
diff --git a/vasl_templates/webapp/tests/fixtures/data/vehicles/landing-craft.json b/vasl_templates/webapp/tests/fixtures/data/vehicles/landing-craft.json
index 54ac820..f042288 100644
--- a/vasl_templates/webapp/tests/fixtures/data/vehicles/landing-craft.json
+++ b/vasl_templates/webapp/tests/fixtures/data/vehicles/landing-craft.json
@@ -1,6 +1,7 @@
[
{ "name": "landing craft",
+ "note_number": "1",
"notes": [ "A" ],
"id": "sh/v:000",
"gpid": [ 399, 397 ]
diff --git a/vasl_templates/webapp/tests/test_aslrb2.py b/vasl_templates/webapp/tests/test_aslrb2.py
new file mode 100644
index 0000000..f6acd5e
--- /dev/null
+++ b/vasl_templates/webapp/tests/test_aslrb2.py
@@ -0,0 +1,117 @@
+""" Test integration with asl-rulebook2. """
+
+import os
+
+from vasl_templates.webapp.tests.utils import init_webapp, find_child, find_children
+from vasl_templates.webapp.tests.test_scenario_persistence import load_scenario
+
+# ---------------------------------------------------------------------
+
+def test_chapter_h( webapp, webdriver ):
+ """Test links to Chapter H vehicle/ordnance notes."""
+
+ # initialize
+ webapp.control_tests.set_app_config_val( "ASL_RULEBOOK2_BASE_URL",
+ os.path.join( os.path.dirname(__file__), "fixtures/asl-rulebook2/vo-note-targets.json" )
+ )
+ init_webapp( webapp, webdriver, scenario_persistence=1 )
+ base_url = "{}/asl-rulebook2/".format( webapp.base_url )
+
+ # test normal vehicles/ordnance
+ load_scenario( {
+ "PLAYER_1": "german",
+ "OB_VEHICLES_1": [ { "name": "a german vehicle" }, { "name": "another german vehicle" } ],
+ "PLAYER_2": "russian",
+ "OB_ORDNANCE_2": [ { "name": "a russian ordnance" }, { "name": "another russian ordnance" } ],
+ } )
+ urls = _unload_aslrb2_urls( base_url )
+ assert urls == [
+ [ [ "gv:1", None ], [] ],
+ [ [], [ None, "ro:2" ] ]
+ ]
+
+ # test Allied/Axis Minor vehicles/ordnance
+ load_scenario( {
+ "PLAYER_1": "dutch",
+ "OB_VEHICLES_1": [ { "name": "dutch vehicle" }, { "name": "common allied minor vehicle" } ],
+ "PLAYER_2": "romanian",
+ "OB_ORDNANCE_2": [ { "name": "romanian ordnance" }, { "name": "common axis minor ordnance" } ],
+ } )
+ urls = _unload_aslrb2_urls( base_url )
+ assert urls == [
+ [ [ "dv:1", "almv:101" ], [] ],
+ [ [], [ "ro:4", "axmo:104", ] ]
+ ]
+
+ # test Landing Craft
+ load_scenario( {
+ "PLAYER_1": "american",
+ "OB_VEHICLES_1": [ { "name": "landing craft" } ],
+ "PLAYER_2": "japanese",
+ "OB_VEHICLES_2": [ { "name": "Daihatsu" } ],
+ } )
+ urls = _unload_aslrb2_urls( base_url )
+ assert urls == [
+ [ [ "lc:1" ], [] ],
+ [ [ "lc:2" ], [] ]
+ ]
+
+ # test derived nationalities
+ load_scenario( {
+ "PLAYER_1": "chinese~gmd",
+ "OB_VEHICLES_1": [ { "name": "a chinese vehicle" } ],
+ } )
+ urls = _unload_aslrb2_urls( base_url )
+ assert urls == [
+ [ ["chv:1"], [] ],
+ [ [], [] ]
+ ]
+
+ # test K:FW (UN Forces)
+ load_scenario( {
+ "PLAYER_1": "american",
+ "OB_VEHICLES_1": [ { "name": "kfw us vehicle" }, { "name": "kfw common vehicle" } ],
+ "PLAYER_2": "british",
+ "OB_ORDNANCE_2": [ { "name": "kfw british ordnance" }, { "name": "kfw common ordnance" } ],
+ } )
+ urls = _unload_aslrb2_urls( base_url )
+ assert urls == [
+ [ ["kfw-un:5","kfw-un:6"], [] ],
+ [ [], ["kfw-un:7","kfw-un:8"] ]
+ ]
+
+ # test K:FW (Communist Forces)
+ load_scenario( {
+ "PLAYER_1": "kfw-kpa",
+ "OB_VEHICLES_1": [ { "name": "kpa vehicle" } ],
+ "PLAYER_2": "kfw-cpva",
+ "OB_ORDNANCE_2": [ { "name": "cpva ordnance" } ],
+ } )
+ urls = _unload_aslrb2_urls( base_url )
+ assert urls == [
+ [ ["kfw-comm:15"], [] ],
+ [ [], ["kfw-comm:16"] ]
+ ]
+
+# ---------------------------------------------------------------------
+
+def _unload_aslrb2_urls( base_url ):
+ """Unload the URL's to the asl-rulebook2 vehicle/ordnance notes."""
+ urls = [
+ [ [], [] ],
+ [ [], [] ]
+ ]
+ for player_no in (1,2):
+ for vo_type_index, vo_type in enumerate(["vehicles","ordnance"]):
+ sortable = find_child( "#ob_{}-sortable_{}".format( vo_type, player_no ) )
+ urls2 = urls[ player_no-1 ][ vo_type_index ]
+ for vo_entry in find_children( ".vo-entry", sortable ):
+ link = find_child( "a.aslrb2", vo_entry )
+ if link:
+ url = link.get_attribute( "href" )
+ if url.startswith( base_url ):
+ url = url[ len(base_url): ]
+ else:
+ url = None
+ urls2.append( url )
+ return urls
diff --git a/vasl_templates/webapp/vo_notes.py b/vasl_templates/webapp/vo_notes.py
index d82c88c..9ef1d71 100644
--- a/vasl_templates/webapp/vo_notes.py
+++ b/vasl_templates/webapp/vo_notes.py
@@ -4,17 +4,22 @@
import os
import io
import re
+import json
import copy
import logging
+import urllib.request
from collections import defaultdict
-from flask import request, render_template, jsonify, send_file, abort, Response, url_for
+from flask import request, render_template, jsonify, send_file, abort, redirect, Response, url_for
from vasl_templates.webapp import app, globvars
from vasl_templates.webapp.files import FileServer
from vasl_templates.webapp.webdriver import WebDriver
from vasl_templates.webapp.utils import read_text_file, resize_image_response, is_image_file, is_empty_file
+_asl_rulebook2_targets = None
+_asl_rulebook2_target_url_template = None
+
# ---------------------------------------------------------------------
@app.route( "/vehicles/notes" )
@@ -351,3 +356,44 @@ def get_vo_notes_report( nat, vo_type ):
NATIONALITY = nat,
VO_TYPE = vo_type
)
+
+# ---------------------------------------------------------------------
+
+@app.route( "/asl-rulebook2/vo-note-targets" )
+def get_asl_rulebook2_vo_note_targets():
+ """Return the Chapter H vehicle/ordnance note targets."""
+ if not _asl_rulebook2_targets:
+ abort( 404 )
+ return jsonify( _asl_rulebook2_targets )
+
+@app.route( "/asl-rulebook2/" )
+def show_asl_rulebook2_target( target ):
+ """Show the specified asl-rulebook2 target."""
+ base_url = app.config.get( "ASL_RULEBOOK2_BASE_URL" )
+ if not base_url:
+ abort( 404 )
+ url = "{}?target={}".format( base_url, target )
+ return redirect( url, code=307 )
+
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+def load_asl_rulebook2_vo_note_targets( msg_store ):
+ """Load the Chapter H vehicle/ordnance note targets."""
+ global _asl_rulebook2_targets, _asl_rulebook2_target_url_template
+ _asl_rulebook2_targets = _asl_rulebook2_target_url_template = None
+ base_url = app.config.get( "ASL_RULEBOOK2_BASE_URL" )
+ if not base_url:
+ return
+ try:
+ if os.path.isfile( base_url ):
+ fp = open( base_url, "r", encoding="utf-8" )
+ else:
+ fp = urllib.request.urlopen( base_url + "/vo-note-targets" )
+ _asl_rulebook2_targets = json.load( fp )
+ except Exception as ex: #pylint: disable=broad-except
+ msg = str( getattr(ex,"reason",None) or ex )
+ msg_store.warning( "Couldn't get the ASL Rulebook2 Chapter H targets: {}".format( msg ) )
+ return
+ _asl_rulebook2_target_url_template = app.config.get( "ASL_RULEBOOK2_TARGET_URL_TEMPLATE",
+ base_url + "/chapter-h/{NAT}/{VO-TYPE}/{ID}"
+ )