diff --git a/vasl_templates/webapp/static/main.js b/vasl_templates/webapp/static/main.js
index 3c1ff49..1ef372f 100644
--- a/vasl_templates/webapp/static/main.js
+++ b/vasl_templates/webapp/static/main.js
@@ -317,7 +317,7 @@ $(document).ready( function () {
edit_template( $(this).data( "id" ) ) ;
} ).html( "
Edit
" )
.attr( "title", "Edit the template." )
- .addClass( "ui-button" ) ;
+ .button( {} ) ;
// watch for changes to the scenario name
$("input[name='SCENARIO_NAME']").on( "input propertychange paste", function() {
@@ -581,6 +581,22 @@ function install_template_pack( data )
update_ob_tab_header( 1 ) ;
update_ob_tab_header( 2 ) ;
}
+
+ // update the snippet buttons
+ function update_button( $btn ) {
+ var template_id = $btn.attr( "data-id" ) ;
+ if ( template_id.substr( 0, 7 ) === "extras/" )
+ return ;
+ if ( template_id.match( /^ob_(vehicles|ordnance).*_[12]$/ ) )
+ template_id = template_id.substring( 0, template_id.length-2 ) ;
+ var enable = is_template_available( template_id ) ;
+ if ( $btn.parent().hasClass( "snippet-control" ) )
+ $btn.parent().controlgroup( enable ? "enable" : "disable" ) ;
+ else
+ $btn.button( enable ? "enable": "disable" ) ;
+ }
+ $( "button.generate" ).each( function() { update_button( $(this) ) ; } ) ;
+ $( "button.edit-template" ).each( function() { update_button( $(this) ) ; } ) ;
}
// --------------------------------------------------------------------
diff --git a/vasl_templates/webapp/static/simple_notes.js b/vasl_templates/webapp/static/simple_notes.js
index 75979de..21c62b4 100644
--- a/vasl_templates/webapp/static/simple_notes.js
+++ b/vasl_templates/webapp/static/simple_notes.js
@@ -125,10 +125,12 @@ function _make_simple_note( note_type, caption )
var buf = [ "" ] ;
if ( ["scenario_notes","ob_setups","ob_notes"].indexOf( note_type ) !== -1 ) {
var note_type0 = note_type.substring( 0, note_type.length-1 ) ;
- buf.push(
- "
"
- ) ;
+ if ( is_template_available( note_type0 ) ) {
+ buf.push(
+ "
"
+ ) ;
+ }
}
buf.push( caption, "
" ) ;
var $content = $( buf.join("") ) ;
diff --git a/vasl_templates/webapp/static/snippets.js b/vasl_templates/webapp/static/snippets.js
index f69c9e3..29700d4 100644
--- a/vasl_templates/webapp/static/snippets.js
+++ b/vasl_templates/webapp/static/snippets.js
@@ -103,6 +103,10 @@ function generate_snippet( $btn, evt, extra_params )
showErrorMsg( "Can't copy to the clipboard:" + escapeHTML(ex) + "
" ) ;
return ;
}
+ // NOTE: This notification will be shown even if there was an error generating the snippet,
+ // but the error message was copied to the clipboard, so it's still techincally correct... :-/
+ // We disabled the ability to generate a snippet if a template file is not present, so it should
+ // only be an issue if there was a problem processing the template.
showInfoMsg( "The HTML snippet has been copied to the clipboard." ) ;
}
diff --git a/vasl_templates/webapp/static/sortable.js b/vasl_templates/webapp/static/sortable.js
index a0d83e9..f9a2822 100644
--- a/vasl_templates/webapp/static/sortable.js
+++ b/vasl_templates/webapp/static/sortable.js
@@ -78,7 +78,7 @@ $.fn.sortable2 = function( action, args )
$sortable2.data( "on_edit", args.edit ) ;
var $add_btn = find_helper( $sortable2, "add" ) ;
$add_btn.prepend( $( " Add
" ) )
- .addClass( "ui-button" ) ;
+ .button( {} ) ;
var $add = find_helper( $sortable2, "add" ) ;
$add.prop( "title", "Add a new " + display_name[0] )
.click( args.add ) ;
@@ -86,7 +86,7 @@ $.fn.sortable2 = function( action, args )
$sortable2.data( "on_reset", args.reset ) ;
var $reset_btn = find_helper( $sortable2, "reset" ) ;
$reset_btn.prepend( $( " Reset
" ) )
- .addClass( "ui-button" ) ;
+ .button( {} ) ;
var $reset = find_helper( $sortable2, "reset" ) ;
$reset.prop( "title", "Reset the " + display_name[1] )
.click( args.reset ) ;
diff --git a/vasl_templates/webapp/static/utils.js b/vasl_templates/webapp/static/utils.js
index 53d4b3a..b556c1c 100644
--- a/vasl_templates/webapp/static/utils.js
+++ b/vasl_templates/webapp/static/utils.js
@@ -57,6 +57,14 @@ function get_scenario_date()
return scenario_date ;
}
+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 ) ;
+ return gTemplatePack.templates[ template_id ] !== undefined ;
+}
+
// --------------------------------------------------------------------
function copyToClipboard( val )
diff --git a/vasl_templates/webapp/static/vassal.js b/vasl_templates/webapp/static/vassal.js
index e31d414..cacdf75 100644
--- a/vasl_templates/webapp/static/vassal.js
+++ b/vasl_templates/webapp/static/vassal.js
@@ -174,6 +174,8 @@ function _generate_snippets()
function on_snippet_button( $btn, inactive ) {
var template_id = $btn.attr( "data-id" ) ;
+ if ( ! is_template_available( template_id ) )
+ return ;
if ( template_id.substr(0,7) === "extras/" ) {
// NOTE: We don't handle extras templates, since they can be parameterized. We would need to store
// the parameter values in the generated snippet, and extract them here so that we can re-generate
diff --git a/vasl_templates/webapp/static/vo.js b/vasl_templates/webapp/static/vo.js
index f2db0b2..6f09c2f 100644
--- a/vasl_templates/webapp/static/vo.js
+++ b/vasl_templates/webapp/static/vo.js
@@ -179,10 +179,12 @@ function do_add_vo( vo_type, player_no, vo_entry, vo_image_id, custom_capabiliti
}
if ( vo_nat ) {
var template_id = (vo_type === "vehicles") ? "ob_vehicle_note" : "ob_ordnance_note" ;
- buf.push(
- ""
- ) ;
+ if ( is_template_available( template_id ) ) {
+ buf.push(
+ ""
+ ) ;
+ }
var url = APP_URL_BASE + "/" + vo_type + "/" + vo_nat + "/note/" ;
data.vo_note_url = url + vo_note_key ;
}
diff --git a/vasl_templates/webapp/tests/test_template_packs.py b/vasl_templates/webapp/tests/test_template_packs.py
index 07b25d0..533e5a0 100644
--- a/vasl_templates/webapp/tests/test_template_packs.py
+++ b/vasl_templates/webapp/tests/test_template_packs.py
@@ -6,12 +6,14 @@ import tempfile
import base64
import re
+import pytest
+
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, \
wait_for_clipboard, get_stored_msg, set_stored_msg, set_stored_msg_marker,\
add_simple_note, for_each_template, find_child, find_children, wait_for, \
- get_droplist_vals_index, init_webapp
+ get_droplist_vals_index, init_webapp, get_css_classes
# ---------------------------------------------------------------------
@@ -134,6 +136,69 @@ def test_nationality_data( webapp, webdriver ):
# ---------------------------------------------------------------------
+@pytest.mark.skipif( pytest.config.option.short_tests, reason="--short-tests specified" ) #pylint: disable=no-member
+def test_missing_templates( webapp, webdriver ):
+ """Test UI updates for missing templates."""
+
+ # initialize
+ init_webapp( webapp, webdriver, template_pack_persistence=1 )
+
+ # get the files in the default template pack
+ files = {}
+ dname = os.path.normpath( os.path.join( os.path.split(__file__)[0], "../data/default-template-pack" ) )
+ for root,_,fnames in os.walk( dname ):
+ for fname in fnames:
+ fname = os.path.join( root, fname )
+ fname2 = os.path.relpath( fname, start=dname )
+ if fname2.startswith( "extras/" ):
+ continue
+ files[ fname2 ] = "dummy template" # nb: we don't care about the content
+
+ def adjust_template_id( template_id ): #pylint: disable=missing-docstring
+ if template_id.startswith( ( "ob_vehicles_", "ob_ordnance_" ) ) and template_id.endswith( ( "_1", "_2" ) ):
+ return template_id[:-2]
+ return template_id
+
+ # upload the template pack, with one file missing each time
+ for fname in files:
+
+ # generate and upload the modified template pack
+ zip_data = _make_zip(
+ { k: v for k,v in files.items() if k != fname }
+ )
+ upload_template_pack_zip( zip_data, False )
+
+ # check the state of each button (everything should be enabled, except for the one
+ # corresponding to the template file we excluded from the upload)
+ def check_buttons( sel, is_snippet_control ): #pylint: disable=missing-docstring
+ for btn in find_children( sel ):
+ # check the UI state of the next button
+ template_id = adjust_template_id( btn.get_attribute( "data-id" ) )
+ expected = os.path.splitext( fname )[0] == template_id
+ disabled = webdriver.execute_script( "return $(arguments[0]).button('option','disabled')", btn )
+ assert expected == disabled
+ # check that snippet control groups have been enabled/disabled correctly
+ parent = btn.find_element_by_xpath( ".." )
+ parent_classes = get_css_classes( parent )
+ if is_snippet_control:
+ assert "snippet-control" in parent_classes
+ elem = find_child( ".ui-selectmenu-button", parent )
+ elem_classes = get_css_classes( elem )
+ if expected:
+ assert "ui-selectmenu-disabled" in elem_classes
+ else:
+ assert "ui-selectmenu-disabled" not in elem_classes
+ else:
+ assert "snippet-control" not in parent_classes
+ check_buttons( "button.generate", True )
+ check_buttons( "button.edit-template", False )
+
+ # NOTE: We should really check that the "generate snippet" buttons don't appear in sortable entries,
+ # but that's more trouble than it's worth - templates such as ob_setup and ob_vehicles are never
+ # going to be missing, since the program becomes kinda pointless if they're not there :-/
+
+# ---------------------------------------------------------------------
+
def _make_zip( files ):
"""Generate a ZIP file."""
with tempfile.NamedTemporaryFile() as temp_file:
diff --git a/vasl_templates/webapp/tests/utils.py b/vasl_templates/webapp/tests/utils.py
index ffcc153..353dc18 100644
--- a/vasl_templates/webapp/tests/utils.py
+++ b/vasl_templates/webapp/tests/utils.py
@@ -539,3 +539,10 @@ def adjust_html( val ):
close_tag = "{}".format( tag[1:] )
val = val.replace( close_tag, close_tag.upper() )
return val
+
+# ---------------------------------------------------------------------
+
+def get_css_classes( elem ):
+ """Get the CSS classes for the specified element."""
+ classes = elem.get_attribute( "class" )
+ return classes.split() if classes else []