diff --git a/vasl_templates/webapp/data/default-template-pack/compass.j2 b/vasl_templates/webapp/data/default-template-pack/compass.j2 new file mode 100644 index 0000000..601197c --- /dev/null +++ b/vasl_templates/webapp/data/default-template-pack/compass.j2 @@ -0,0 +1,5 @@ + + + + + diff --git a/vasl_templates/webapp/data/default-template-pack/extras/compass.j2 b/vasl_templates/webapp/data/default-template-pack/extras/compass.j2 deleted file mode 100644 index 6cf91a2..0000000 --- a/vasl_templates/webapp/data/default-template-pack/extras/compass.j2 +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/vasl_templates/webapp/static/css/main.css b/vasl_templates/webapp/static/css/main.css index 7b41066..781e30e 100644 --- a/vasl_templates/webapp/static/css/main.css +++ b/vasl_templates/webapp/static/css/main.css @@ -7,7 +7,7 @@ body { font-family: Arial, Helvetica, sans-serif ; font-size: 16px ; } ul, ol { margin: 0.5em 0 0 1.25em ; } input[type="text"] { height: 20px ; border: 1px solid #c5c5c5 ; padding: 0 2px ; } -label { height: 1.25em ; margin-top: -3px ; } +label { height: 1.25em ; } /* -------------------------------------------------------------------- */ @@ -29,7 +29,7 @@ label { height: 1.25em ; margin-top: -3px ; } .select2-dropdown { color: #444 ; } -.snippet-control button.generate { height: 26px ; padding: 2px 10px 2px 5px ; color: #000 ; } +.snippet-control button.generate { height: 26px ; padding: 2px 0 2px 5px ; color: #000 ; } .snippet-control button.generate.inactive { color: #aaa ; } .snippet-control button.generate img { height: 20px ; margin-right: 5px ; vertical-align: middle ; } .snippet-control .ui-selectmenu-button { padding: 2px 10px ; } diff --git a/vasl_templates/webapp/static/css/tabs-scenario.css b/vasl_templates/webapp/static/css/tabs-scenario.css index 74447e7..7e96207 100644 --- a/vasl_templates/webapp/static/css/tabs-scenario.css +++ b/vasl_templates/webapp/static/css/tabs-scenario.css @@ -2,39 +2,32 @@ #panel-scenario { display: flex ; flex-direction: column ; } -#panel-scenario .row { display: flex ; align-items: center ; } +#panel-scenario .row { display: flex ; align-items: center ; margin-bottom: 2px ; } #panel-scenario input { flex-grow: 1 ; } #panel-scenario input[name='SCENARIO_ID'] { margin-left: 0.25em ; width: 80px ; flex-grow: 0 ; text-align: right ; } -#panel-scenario .scenario-search { width: 25px ; height: 22px ; margin: 0 0 0 0.25em ; padding: 0 ; margin-top:-4px; } +#panel-scenario .scenario-search { width: 25px ; height: 22px ; margin: 0 0 0 0.25em ; padding: 0 ; } #panel-scenario .scenario-search img { margin-top: 2px ; width: 16px ; } #panel-scenario input[name='SCENARIO_DATE'] { width: 6em ; flex-grow: 0 ; } -#panel-scenario label[for='TURN_TRACK_NTURNS'] { margin-top: 2px ; } #panel-scenario button#turn-track-settings { width: 25px ; height: 24px ; margin-right: 5px ; padding: 3px 2px 2px 2px ; } -#panel-scenario label[for='PLAYER_1'] { margin-top: 2px ; } #panel-scenario .select2[name="PLAYER_1"] { flex: 1 ; } -#panel-scenario label[for='PLAYER_2'] { margin-top: 2px ; } #panel-scenario .select2[name="PLAYER_2"] { flex: 1 ; } #panel-scenario input[name="PLAYER_1_DESCRIPTION"], #panel-scenario input[name="PLAYER_2_DESCRIPTION"] { - margin-left: 6.35em ; margin-top: 1px ; font-size: 75% ; + font-size: 75% ; } -#panel-scenario label { font-weight: bold ; width: 4.75em ; } +#panel-scenario label { margin-top: 2px ; font-weight: bold ; width: 4.75em ; } #panel-scenario label.header { font-weight: bold ; width: 3em ; text-align: center ; } -#panel-scenario input { margin-bottom: 0.25em ; } #panel-scenario .select2-container { margin-right: 2px ; } #panel-scenario .select2-selection__rendered { height: 23px ; line-height: 23px ; } #panel-scenario .select2-selection__arrow { margin-top: -2px ; } #panel-scenario .select2-selection { height: 24px !important ; border-radius: 0 !important ; } -#panel-scenario .select2[name="SCENARIO_THEATER"] { margin-left: 0.25em ; margin-right: 0 ; } -#panel-scenario .select2-container[name="SCENARIO_THEATER"] .select2-selection { height: 22px !important ; margin-top: -4px ; } -#panel-scenario .select2-container[name="SCENARIO_THEATER"] .select2-selection__rendered { height: 20px ; line-height: 20px ; } -#panel-scenario .select2-container[name="SCENARIO_THEATER"] .select2-selection__arrow { margin-top: -6px ; } +#panel-scenario .select2[name="SCENARIO_THEATER"] { margin-left: 0.25em ; margin-right: 0.25em ; } /* -------------------------------------------------------------------- */ diff --git a/vasl_templates/webapp/static/images/compass/none.png b/vasl_templates/webapp/static/images/compass/none.png new file mode 100644 index 0000000..a7a36dc Binary files /dev/null and b/vasl_templates/webapp/static/images/compass/none.png differ diff --git a/vasl_templates/webapp/static/main.js b/vasl_templates/webapp/static/main.js index 2ffcd7f..b080798 100644 --- a/vasl_templates/webapp/static/main.js +++ b/vasl_templates/webapp/static/main.js @@ -391,6 +391,23 @@ $(document).ready( function () { // replace all the "generate" buttons with "generate/edit" button/droplist's $("button.generate").each( function() { init_snippet_button( $(this) ) ; } ) ; + // add special options to the COMPASS snippet button menu + var $compassMenu = $( "select[data-id='compass']" ) ; + var compassDirns = [ "", "right", "left", "down", "up" ] ; + compassDirns.forEach( function( dirn ) { + var caption = (dirn === "") ? "-" : dirn[0].toUpperCase() + dirn.substring(1) ; + $compassMenu.prepend( + "" + ) ; + } ) ; + $( ".snippet-control[data-id='compass'] select" ).on( "selectmenuselect", function( evt, ui ) { + var dirn = ui.item.value ; + if ( ! compassDirns.includes( dirn ) ) + return ; + $( "input.param[name='COMPASS']" ).val( dirn ) ; + updateCompassImage() ; + } ) ; + // handle requests to edit the templates $("button.edit-template").click( function() { edit_template( $(this).data( "id" ) ) ; @@ -555,7 +572,9 @@ function init_snippet_button( $btn ) var fname="snippet.png", style="" ; if ( template_id.substring( 0, 9 ) === "nat_caps_" ) { fname = "nat-caps.png" ; - style = "height:15px;margin-right:0;" ; + style = "height:15px;" ; + } else if ( template_id == "compass" ) { + fname = "compass/none.png" ; } $newBtn.find( "button" ) .prepend( $( "" ) ) @@ -564,7 +583,7 @@ function init_snippet_button( $btn ) return false ; } ) .attr( "title", GENERATE_SNIPPET_HINT ) - .css( { "padding-right": $btn.text() !== "" ? "10px" : "0" } ) ; + .css( { "padding-right": $btn.text() !== "" ? "5px" : "0" } ) ; // add in the droplist $newBtn.controlgroup() ; @@ -591,6 +610,22 @@ function init_snippet_button( $btn ) $btn.replaceWith( $newBtn ) ; } +function updateCompassImage() { + // update the image in the COMPASS snippet button + var dirn = $( "input.param[name='COMPASS']" ).val() || "none" ; + var $btn = $( "button.generate[data-id='compass']" ) ; + var imagePadding = { + up: "2px 0 0 0", down: "0 0 2px 0", left: "0", right: "0", + none: "0" + } ; + $btn.find( "img" ).attr( "src", + make_app_url( "/static/images/compass/" + dirn + ".png" ) + ).css( { + padding: imagePadding[dirn] + } ) ; + $btn.button( dirn === "none" ? "disable" : "enable" ) ; +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - gPageLoadStatus = [ diff --git a/vasl_templates/webapp/static/scenarios.js b/vasl_templates/webapp/static/scenarios.js index 7adf829..bad59ba 100644 --- a/vasl_templates/webapp/static/scenarios.js +++ b/vasl_templates/webapp/static/scenarios.js @@ -708,6 +708,10 @@ function doImportScenario( scenario ) $(this).prop( "checked", false ) ; } ) ; + // reset the compass + $( "#panel-scenario input[name='COMPASS']" ).val( "" ) ; + updateCompassImage() ; + // NOTE: We could reset the ELR/SAN here, but if the user is importing on top of an existing setup, // the most likely reason is because they want to connect it to an ASA scenario, not because // they want to import a whole set of new details, so clearing the ELR/SAN wouldn't make sense. diff --git a/vasl_templates/webapp/static/snippets.js b/vasl_templates/webapp/static/snippets.js index 1d6e8f3..894240d 100644 --- a/vasl_templates/webapp/static/snippets.js +++ b/vasl_templates/webapp/static/snippets.js @@ -1888,6 +1888,7 @@ function do_load_scenario_data( params ) gLastSavedScenario = unload_params_for_save( false ) ; // update the UI + updateCompassImage() ; $("#tabs").tabs( "option", "active", 0 ) ; on_scenario_date_change() ; update_scenario_status() ; diff --git a/vasl_templates/webapp/static/vassal.js b/vasl_templates/webapp/static/vassal.js index 053415e..69e9379 100644 --- a/vasl_templates/webapp/static/vassal.js +++ b/vasl_templates/webapp/static/vassal.js @@ -213,6 +213,8 @@ function _get_raw_content( snippet_id, $btn, params ) return get_values([ "VICTORY_CONDITIONS" ]) ; if ( snippet_id === "turn_track" ) return true ; + if ( snippet_id === "compass" && get_values(["COMPASS"]).length > 0 ) + return true ; if ( snippet_id === "players" ) { return [ "ELR:", "SAN:", diff --git a/vasl_templates/webapp/templates/tabs-scenario.html b/vasl_templates/webapp/templates/tabs-scenario.html index 094d714..68181d2 100644 --- a/vasl_templates/webapp/templates/tabs-scenario.html +++ b/vasl_templates/webapp/templates/tabs-scenario.html @@ -14,17 +14,19 @@ + +
- - Width: + + Width:
-
+
-
+
@@ -52,9 +54,10 @@ - +
+
@@ -62,18 +65,19 @@ - +
+
- + Width: - +
diff --git a/vasl_templates/webapp/tests/fixtures/data/default-template-pack/compass.j2 b/vasl_templates/webapp/tests/fixtures/data/default-template-pack/compass.j2 new file mode 100644 index 0000000..78d5c60 --- /dev/null +++ b/vasl_templates/webapp/tests/fixtures/data/default-template-pack/compass.j2 @@ -0,0 +1 @@ +COMPASS: {{COMPASS}} diff --git a/vasl_templates/webapp/tests/fixtures/template-packs/full/compass.j2 b/vasl_templates/webapp/tests/fixtures/template-packs/full/compass.j2 new file mode 100644 index 0000000..b2246be --- /dev/null +++ b/vasl_templates/webapp/tests/fixtures/template-packs/full/compass.j2 @@ -0,0 +1 @@ +Customized COMPASS. diff --git a/vasl_templates/webapp/tests/fixtures/template-packs/new-default/compass.j2 b/vasl_templates/webapp/tests/fixtures/template-packs/new-default/compass.j2 new file mode 100644 index 0000000..746c8a0 --- /dev/null +++ b/vasl_templates/webapp/tests/fixtures/template-packs/new-default/compass.j2 @@ -0,0 +1 @@ +New default COMPASS. diff --git a/vasl_templates/webapp/tests/test_scenario_persistence.py b/vasl_templates/webapp/tests/test_scenario_persistence.py index 2e1b832..34d4186 100644 --- a/vasl_templates/webapp/tests/test_scenario_persistence.py +++ b/vasl_templates/webapp/tests/test_scenario_persistence.py @@ -16,7 +16,7 @@ from vasl_templates.webapp.tests.utils import \ ALL_SCENARIO_PARAMS = { "scenario": [ "SCENARIO_NAME", "SCENARIO_ID", - "SCENARIO_LOCATION", "SCENARIO_THEATER", + "SCENARIO_LOCATION", "SCENARIO_THEATER", "COMPASS", "SCENARIO_DATE", "SCENARIO_WIDTH", "ASA_ID", "ROAR_ID", "PLAYER_1", "PLAYER_1_ELR", "PLAYER_1_SAN", "PLAYER_1_DESCRIPTION", @@ -67,6 +67,7 @@ def test_scenario_persistence( webapp, webdriver ): #pylint: disable=too-many-st "SCENARIO_NAME": "my test scenario", "SCENARIO_ID": "xyz123", "SCENARIO_LOCATION": "right here", + "COMPASS": "right", "SCENARIO_THEATER": "PTO", "SCENARIO_DATE": "12/31/1945", "SCENARIO_WIDTH": "101", diff --git a/vasl_templates/webapp/tests/test_snippets.py b/vasl_templates/webapp/tests/test_snippets.py index 7026d53..c0da5c5 100644 --- a/vasl_templates/webapp/tests/test_snippets.py +++ b/vasl_templates/webapp/tests/test_snippets.py @@ -12,8 +12,8 @@ from vasl_templates.webapp.tests.utils import \ get_stored_msg, set_stored_msg_marker, find_child, find_children, adjust_html, \ for_each_template, add_simple_note, edit_simple_note, \ get_sortable_entry_count, generate_sortable_entry_snippet, drag_sortable_entry_to_trash, \ - new_scenario, set_scenario_date, set_turn_track_nturns -from vasl_templates.webapp.tests.test_scenario_persistence import load_scenario, load_scenario_params + new_scenario, set_scenario_date +from vasl_templates.webapp.tests.test_scenario_persistence import load_scenario # --------------------------------------------------------------------- @@ -25,14 +25,14 @@ def test_snippet_ids( webapp, webdriver ): init_webapp( webapp, webdriver, scenario_persistence=1 ) # load a scenario (so that we get some sortable's) - scenario_data = { + load_scenario( { + "COMPASS": "left", "SCENARIO_NOTES": [ { "caption": "Scenario note #1" } ], "OB_SETUPS_1": [ { "caption": "OB setup note #1" } ], "OB_NOTES_1": [ { "caption": "OB note #1" } ], "OB_SETUPS_2": [ { "caption": "OB setup note #2" } ], "OB_NOTES_2": [ { "caption": "OB note #2" } ], - } - load_scenario( scenario_data ) + } ) def check_snippet( btn ): """Generate a snippet and check that it has an ID.""" @@ -59,7 +59,10 @@ def test_snippet_ids( webapp, webdriver ): # test snippets with British/American new_scenario() - load_scenario_params( { "scenario": { "PLAYER_1": "british", "PLAYER_2": "american" } } ) + load_scenario( { + "PLAYER_1": "british", "PLAYER_2": "american", + "COMPASS": "right", + } ) do_test( "" ) do_test( "11/01/1942" ) @@ -231,8 +234,11 @@ def test_edit_templates( webapp, webdriver ): # initialize webapp.control_tests.set_vo_notes_dir( "{TEST}" ) - init_webapp( webapp, webdriver, edit_template_links=1 ) - set_turn_track_nturns( "3" ) + init_webapp( webapp, webdriver, scenario_persistence=1, edit_template_links=1 ) + load_scenario( { + "TURN_TRACK": { "NTURNS": 3 }, + "COMPASS": "down", + } ) ob_setups = { 1: find_child( "#ob_setups-sortable_1" ), 2: find_child( "#ob_setups-sortable_2" ) diff --git a/vasl_templates/webapp/tests/test_template_packs.py b/vasl_templates/webapp/tests/test_template_packs.py index 272ad78..46573b5 100644 --- a/vasl_templates/webapp/tests/test_template_packs.py +++ b/vasl_templates/webapp/tests/test_template_packs.py @@ -9,6 +9,7 @@ import random from selenium.webdriver.common.by import By from vasl_templates.webapp.utils import TempFile +from vasl_templates.webapp.tests.test_scenario_persistence import load_scenario from vasl_templates.webapp.tests.test_vehicles_ordnance import add_vo from vasl_templates.webapp.tests.utils import \ select_tab, select_menu_option, set_player, set_turn_track_nturns, \ @@ -90,8 +91,11 @@ def test_new_default_template_pack( webapp, webdriver ): webapp.control_tests \ .set_default_template_pack( "new-default/" ) \ .set_vo_notes_dir( "{TEST}" ) - init_webapp( webapp, webdriver ) - set_turn_track_nturns( "3" ) + init_webapp( webapp, webdriver, scenario_persistence=1 ) + load_scenario( { + "COMPASS": "north", + "TURN_TRACK": { "NTURNS": 3 }, + } ) # check that the new templates are being used _do_test_default_template_pack( webdriver ) @@ -106,8 +110,11 @@ def test_new_default_template_pack_zip( webapp, webdriver ): webapp.control_tests \ .set_default_template_pack( zip_data ) \ .set_vo_notes_dir( "{TEST}" ) - init_webapp( webapp, webdriver ) - set_turn_track_nturns( "3" ) + init_webapp( webapp, webdriver, scenario_persistence=1 ) + load_scenario( { + "COMPASS": "north", + "TURN_TRACK": { "NTURNS": 3 }, + } ) # check that the new templates are being used _do_test_default_template_pack( webdriver ) diff --git a/vasl_templates/webapp/tests/test_user_settings.py b/vasl_templates/webapp/tests/test_user_settings.py index 60b72fa..e415d78 100644 --- a/vasl_templates/webapp/tests/test_user_settings.py +++ b/vasl_templates/webapp/tests/test_user_settings.py @@ -302,6 +302,7 @@ def test_alternate_webapp_base_url( webapp, webdriver ): load_scenario( { "SCENARIO_NAME": "test scenario", "SCENARIO_DATE": "01/01/1940", + "COMPASS": "north", "VICTORY_CONDITIONS": "Just do it!", "SCENARIO_NOTES": [ { "caption": "Scenario note #1" } ], "SSR": [ "SSR #1", "SSR #2", "SSR #3" ], diff --git a/vasl_templates/webapp/tests/test_vassal.py b/vasl_templates/webapp/tests/test_vassal.py index 3edc388..b99d670 100644 --- a/vasl_templates/webapp/tests/test_vassal.py +++ b/vasl_templates/webapp/tests/test_vassal.py @@ -38,6 +38,7 @@ def test_full_update( webapp, webdriver ): "SCENARIO_ID": "xyz123", "SCENARIO_LOCATION": "Right here", "SCENARIO_THEATER": "PTO", + "COMPASS": "", "SCENARIO_DATE": "12/31/1945", "SCENARIO_WIDTH": "101", "ASA_ID": "", "ROAR_ID": "", @@ -564,7 +565,7 @@ def test_player_owned_labels( webapp, webdriver ): # - players (new American player) fname = os.path.join( os.path.split(__file__)[0], "fixtures/update-vsav/player-owned-labels-legacy.vsav" ) updated_vsav_dump = _update_vsav_and_dump( webapp, fname, - { "created": 2, "updated": 4 } + { "created": 2, "updated": 4 } ) _check_vsav_dump( updated_vsav_dump , { "german/ob_setup_1.1": "german setup #1", @@ -770,6 +771,65 @@ def test_vo_entry_selection_for_theater( webapp, webdriver ): # --------------------------------------------------------------------- +def test_compass( webapp, webdriver ): + """Test creating compass labels.""" + + # NOTE: We're only interested in what happens with the compass label, we ignore everything else. + ignore_labels = [ "scenario", "players", "victory_conditions", + "german/nat_caps_1", "russian/nat_caps_2", + ] + + def do_test(): #pylint: disable=missing-docstring + + # initialize + webapp.control_tests.set_data_dir( "{REAL}" ) + init_webapp( webapp, webdriver, scenario_persistence=1, vsav_persistence=1 ) + + # NOTE: We don't test the simple case of updating a scenario without specifying a compass direction + # since that is done in the other tests that pre-date the compass label. + + # update a scenario with the compass direction set + load_scenario( { "COMPASS": "left" } ) + fname = os.path.join( os.path.split(__file__)[0], "fixtures/update-vsav/empty.vsav" ) + vsav_data = _update_vsav( fname, + { "created": 6 } + ) + with TempFile() as temp_file: + temp_file.write( vsav_data ) + temp_file.close( delete=False ) + vsav_dump = _dump_vsav( webapp, temp_file.name ) + _check_vsav_dump( vsav_dump, { + "compass": "compass/left.png", + }, ignore_labels ) + + # update the scenario with a different compass direction + load_scenario( { "COMPASS": "right" } ) + vsav_data = _update_vsav( temp_file.name, + { "updated": 2 } + ) + with TempFile() as temp_file2: + temp_file2.write( vsav_data ) + temp_file2.close( delete=False ) + vsav_dump = _dump_vsav( webapp, temp_file2.name ) + _check_vsav_dump( vsav_dump, { + "compass": "compass/right.png", + }, ignore_labels ) + + # update the scenario with the compass disabled + load_scenario( { "COMPASS": "" } ) + vsav_data = _update_vsav( temp_file2.name, + { "updated": 1, "deleted": 1 } + ) + with TempFile() as temp_file3: + temp_file3.write( vsav_data ) + temp_file3.close( delete=False ) + vsav_dump = _dump_vsav( webapp, temp_file3.name ) + _check_vsav_dump( vsav_dump, {}, ignore_labels ) + + run_vassal_tests( webapp, do_test, all_combos=False ) + +# --------------------------------------------------------------------- + def run_vassal_tests( webapp, func, vasl_extns_type=None, all_combos=None, min_vasl_version=None, max_vasl_version=None, ignore_vasl_versions=None ): diff --git a/vasl_templates/webapp/tests/utils.py b/vasl_templates/webapp/tests/utils.py index 851053a..e750c1e 100644 --- a/vasl_templates/webapp/tests/utils.py +++ b/vasl_templates/webapp/tests/utils.py @@ -25,6 +25,7 @@ _STD_TEMPLATES = { "scenario", "players", "victory_conditions", "scenario_notes", "ssr", "nat_caps_1", # nb: "nat_caps_2" is functionally the same as this "turn_track", # nb: this will only be used if a turn count has been specified + "compass", ], "ob1": [ "ob_setup_1", "ob_note_1", "ob_vehicles_1", "ob_vehicle_note_1", "ob_vehicles_ma_notes_1",