Added OB notes.

master
Pacman Ghost 6 years ago
parent 13ae3074cc
commit 2e84510353
  1. 13
      vasl_templates/webapp/data/default-template-pack/ob_note.j2
  2. 10
      vasl_templates/webapp/static/css/main.css
  3. 28
      vasl_templates/webapp/static/css/tabs-ob.css
  4. 30
      vasl_templates/webapp/static/main.js
  5. 87
      vasl_templates/webapp/static/ob_setup.js
  6. 118
      vasl_templates/webapp/static/simple_notes.js
  7. 26
      vasl_templates/webapp/static/snippets.js
  8. 37
      vasl_templates/webapp/templates/index.html
  9. 1
      vasl_templates/webapp/tests/fixtures/data/default-template-pack/ob_note.j2
  10. 1
      vasl_templates/webapp/tests/fixtures/template-packs/full/ob_note.j2
  11. 1
      vasl_templates/webapp/tests/fixtures/template-packs/new-default/ob_note.j2
  12. 99
      vasl_templates/webapp/tests/test_ob.py
  13. 28
      vasl_templates/webapp/tests/test_scenario_persistence.py
  14. 29
      vasl_templates/webapp/tests/test_snippets.py
  15. 20
      vasl_templates/webapp/tests/test_template_packs.py
  16. 25
      vasl_templates/webapp/tests/utils.py

@ -0,0 +1,13 @@
<html>
<table>
<tr>
<td style="
{%if OB_NOTE_WIDTH%} width: {{OB_NOTE_WIDTH}} ; {%endif%}
">
{{OB_NOTE}}
</table>
</html>

@ -111,11 +111,11 @@ input[type="text"] { margin-bottom: 0.25em ; }
.ui-dialog.edit-ssr textarea { resize: none ; width: calc(100% - 4px) ; height: calc(100% - 1.25em) ; }
.ui-dialog.edit-ssr button { margin: 0 0 0 5px ; padding: 0.1em 0.2em ; }
.ui-dialog.edit-ob_setup .ui-dialog-titlebar { display: none ; }
.ui-dialog.edit-ob_setup .ui-dialog-buttonpane { border: none ; padding: 0 ; font-size: 75% ; }
#edit-ob_setup { padding: 2px ; }
.ui-dialog.edit-ob_setup textarea { resize: none ; width: calc(100% - 4px) ; height: calc(100% - 3em) ; }
.ui-dialog.edit-ob_setup button { margin: 0 0 0 5px ; padding: 0.1em 0.2em ; }
.ui-dialog.edit-simple_note .ui-dialog-titlebar { display: none ; }
.ui-dialog.edit-simple_note .ui-dialog-buttonpane { border: none ; padding: 0 ; font-size: 75% ; }
#edit-simple_note { padding: 2px ; }
.ui-dialog.edit-simple_note textarea { resize: none ; width: calc(100% - 4px) ; height: calc(100% - 3em) ; }
.ui-dialog.edit-simple_note button { margin: 0 0 0 5px ; padding: 0.1em 0.2em ; }
#select-vo { overflow: hidden ; }
#select-vo .header { height: 2em ; }

@ -1,22 +1,22 @@
/* -------------------------------------------------------------------- */
.panel-ob_setup {
.panel-ob_setups {
height: 100% ;
display: grid ; display: -ms-grid ;
grid-template-rows: 1fr 2em ; -ms-grid-rows: 1fr 2em ;
grid-template-columns: 1fr ; -ms-grid-columns: 1fr ;
}
/* FUDGE! IE hackamathon follows... */
.panel-ob_setup .content { -ms-grid-row: 1 ; -ms-grid-column: 1 ; }
.panel-ob_setup .footer { -ms-grid-row: 2 ; -ms-grid-column: 1 ; }
.panel-ob_setups .content { -ms-grid-row: 1 ; -ms-grid-column: 1 ; }
.panel-ob_setups .footer { -ms-grid-row: 2 ; -ms-grid-column: 1 ; }
.panel-ob_setup ul.sortable li input[type="button"] { float: right ; }
.panel-ob_setup .footer { text-align: right ; font-size: 75% ; }
.panel-ob_setup .footer .l { float: left ; }
.ob_setup-trash { margin-left: 5px ; height: 2em ; }
.panel-ob_setups ul.sortable li input[type="button"] { float: right ; }
.panel-ob_setups .footer { text-align: right ; font-size: 75% ; }
.panel-ob_setups .footer .l { float: left ; }
.ob_setups-trash { margin-left: 5px ; height: 2em ; }
.ob_setup-hint { width:100% ; height: calc(100% - 1.5em) ; font-size: 80% ; font-style: italic ; }
.ob_setup-hint p { margin-bottom: 1em ; }
.ob_setups-hint { width:100% ; height: calc(100% - 1.5em) ; font-size: 80% ; font-style: italic ; }
.ob_setups-hint p { margin-bottom: 1em ; }
/* -------------------------------------------------------------------- */
@ -30,8 +30,16 @@
.panel-ob_notes .content { -ms-grid-row: 1 ; -ms-grid-column: 1 ; }
.panel-ob_notes .footer { -ms-grid-row: 2 ; -ms-grid-column: 1 ; }
.panel-ob_notes ul.sortable li input[type="button"] { float: right ; }
.panel-ob_notes .footer { font-size: 75% ; }
.panel-ob_notes div.snippet-control { float: left ; margin: 0.25em 0.25em 0 0 ; }
.panel-ob_notes .footer input[type="button"][data-id="ob_note"] { float: right ; }
.panel-ob_notes div.snippet-control { float: right ; margin: 0.25em 0.25em 0 0 ; }
.panel-ob_notes .footer .l { float: left ; }
.ob_notes-trash { margin-left: 5px ; height: 2em ; }
.ob_notes-hint { width:100% ; height: calc(100% - 1.5em) ; font-size: 80% ; font-style: italic ; }
.ob_notes-hint p { margin-bottom: 1em ; }
/* -------------------------------------------------------------------- */

@ -88,22 +88,37 @@ $(document).ready( function () {
} ) ;
enable_ctrl_enter( $("#edit-ssr"), "OK" ) ;
// initialize OB setup controls
init_sortable( $("#ob_setup-sortable_1"),
// initialize the OB setups
init_sortable( $("#ob_setups-sortable_1"),
function() { add_ob_setup(1) ; },
edit_ob_setup
) ;
$("#panel-ob_setup1 input[type='button'][data-id='ob_setup']").click( function() {
$("#panel-ob_setups1 input[type='button'][data-id='ob_setup']").click( function() {
edit_template( "ob_setup" ) ;
} ) ;
init_sortable( $("#ob_setup-sortable_2"),
init_sortable( $("#ob_setups-sortable_2"),
function() { add_ob_setup(2) ; },
edit_ob_setup
) ;
$("#panel-ob_setup2 input[type='button'][data-id='ob_setup']").click( function() {
$("#panel-ob_setups2 input[type='button'][data-id='ob_setup']").click( function() {
edit_template( "ob_setup" ) ;
} ) ;
enable_ctrl_enter( $("#edit-ob_setup"), "OK" ) ;
// initialize the OB notes
init_sortable( $("#ob_notes-sortable_1"),
function() { add_ob_note(1) ; },
edit_ob_note
) ;
$("#panel-ob_notes1 input[type='button'][data-id='ob_note']").click( function() {
edit_template( "ob_note" ) ;
} ) ;
init_sortable( $("#ob_notes-sortable_2"),
function() { add_ob_note(2) ; },
edit_ob_note
) ;
$("#panel-ob_notes2 input[type='button'][data-id='ob_note']").click( function() {
edit_template( "ob_note" ) ;
} ) ;
// initialize vehicle controls (1)
$("#vehicle-sortable_1").sortable( { connectWith: "#vehicle-trash_1", cursor: "move" } ) ;
@ -260,6 +275,9 @@ $(document).ready( function () {
} ) ;
enable_ctrl_enter( $("#edit-template"), "Close" ) ;
// enable Ctrl-Enter when editing simple notes
enable_ctrl_enter( $("#edit-simple_note"), "OK" ) ;
// initialize hotkeys
init_hotkeys() ;

@ -1,87 +0,0 @@
// --------------------------------------------------------------------
function add_ob_setup( player_id )
{
// add a new OB setup
edit_ob_setup( $("#ob_setup-sortable_"+player_id), null ) ;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
function edit_ob_setup( $sortable, $entry )
{
var $caption, $width ;
// let the user edit the OB setup
$("#edit-ob_setup").dialog( {
dialogClass: "edit-ob_setup",
modal: true,
minWidth: 400,
minHeight: 150,
open: function() {
$caption = $(this).children( "textarea" ) ;
$width = $(this).children( "input[type='text']" ) ;
if ( $entry ) {
var data = $entry.data( "sortable-data" ) ;
$caption.val( data.caption ) ;
$width.val( data.width ) ;
}
else {
$caption.val( "" ) ;
$width.val( "" ) ;
}
$(this).height( $(this).height() ) ; // fudge: force the textarea to resize
},
buttons: {
OK: function() {
var caption = $caption.val().trim() ;
var width = $width.val().trim() ;
if ( $entry ) {
// update the existing OB setup
if ( caption === "" )
delete_sortable_entry( $entry ) ;
else {
$entry.data("sortable-data").caption = caption ;
$entry.data("sortable-data").width = width ;
$entry.empty().append( _make_sortable_entry( caption ) ) ;
}
}
else {
// create a new OB setup
if ( caption !== "" ) {
data = { caption: caption, width: width } ;
do_add_ob_setup( $sortable, data ) ;
}
}
$(this).dialog( "close" ) ;
},
Cancel: function() { $(this).dialog( "close" ) ; },
},
} ) ;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
function do_add_ob_setup( $sortable, data )
{
// add a new sortable entry
add_sortable( $sortable, _make_sortable_entry(data.caption), data ) ;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
function _make_sortable_entry( caption )
{
// generate the sortable entry
var $content = $( "<div><input type='button' data-id='ob_setup' value='Snippet'>" + caption + "</div>" ) ;
// add a handler for the snippet button
$content.children("input[type='button']").click( function() {
var data = $(this).parent().parent().data( "sortable-data" ) ;
var extra_params = { OB_SETUP: data.caption, OB_SETUP_WIDTH: data.width } ;
generate_snippet( $(this), extra_params ) ;
} ) ;
return $content ;
}

@ -0,0 +1,118 @@
// NOTE: This module manage simple notes (some text and an optional width),
// which is used by OB setups and OB notes (which differ only in their templates,
// the code to manage them is almost identical).
// --------------------------------------------------------------------
function add_ob_setup( player_id ) { _do_edit_simple_note( $("#ob_setups-sortable_"+player_id), null ) ; }
function do_add_ob_setup( $sortable, data ) { _do_add_simple_note($sortable,data) ; }
function edit_ob_setup( $sortable, $entry ) { _do_edit_simple_note( $sortable, $entry ) ; }
function add_ob_note( player_id ) { _do_edit_simple_note( $("#ob_notes-sortable_"+player_id), null ) ; }
function do_add_ob_note( $sortable, data ) { _do_add_simple_note($sortable,data) ; }
function edit_ob_note( $sortable, $entry ) { _do_edit_simple_note( $sortable, $entry ) ; }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
function _do_edit_simple_note( $sortable, $entry )
{
// figure out what we're editing
var note_type = _get_note_type_for_sortable( $sortable ) ;
var note_type0 = note_type.substring( 0, note_type.length-1 ) ; // plural -> singular :-/
// let the user edit the note
var $caption, $width ;
$("#edit-simple_note").dialog( {
dialogClass: "edit-simple_note",
modal: true,
minWidth: 400,
minHeight: 150,
open: function() {
$caption = $(this).children( "textarea" ) ;
$width = $(this).children( "input[type='text']" ) ;
if ( $entry ) {
var data = $entry.data( "sortable-data" ) ;
$caption.val( data.caption ) ;
$width.val( data.width ) ;
}
else {
$caption.val( "" ) ;
$width.val( "" ) ;
}
$(this).height( $(this).height() ) ; // fudge: force the textarea to resize
},
buttons: {
OK: function() {
var caption = $caption.val().trim() ;
var width = $width.val().trim() ;
if ( $entry ) {
// update the existing note
if ( caption === "" )
delete_sortable_entry( $entry ) ;
else {
$entry.data("sortable-data").caption = caption ;
$entry.data("sortable-data").width = width ;
$entry.empty().append( _make_simple_note( note_type, caption ) ) ;
}
}
else {
// create a new note
if ( caption !== "" ) {
data = { caption: caption, width: width } ;
_do_add_simple_note( $sortable, data ) ;
}
}
$(this).dialog( "close" ) ;
},
Cancel: function() { $(this).dialog( "close" ) ; },
},
} ) ;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
function _do_add_simple_note( $sortable, data )
{
// add a new sortable entry
var note_type = _get_note_type_for_sortable( $sortable ) ;
var $entry = _make_simple_note( note_type, data.caption ) ;
add_sortable( $sortable, $entry , data ) ;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
function _make_simple_note( note_type, caption )
{
// generate the sortable entry
var note_type0 = note_type.substring( 0, note_type.length-1 ) ;
var buf = [] ;
buf.push(
"<div>",
"<input type='button' data-id='" + note_type0 + "' value='Snippet'>",
caption,
"</div>"
) ;
var $content = $( buf.join("") ) ;
// add a handler for the snippet button
$content.children("input[type='button']").click( function() {
var data = $(this).parent().parent().data( "sortable-data" ) ;
var prefix = (note_type === "ob_setups") ? "OB_SETUP" : "OB_NOTE" ;
var extra_params = {} ;
extra_params[prefix] = data.caption ;
extra_params[prefix+"_WIDTH"] = data.width ;
generate_snippet( $(this), extra_params ) ;
} ) ;
return $content ;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
function _get_note_type_for_sortable( $sortable )
{
// figure out what type of note the sortable has
var id = $sortable.prop( "id" ) ;
var match = /^(ob_(setups|notes))-sortable_\d$/.exec( id ) ;
return match[1] ;
}

@ -503,13 +503,22 @@ function do_load_scenario( params )
params_loaded[key] = true ;
continue ;
}
var player_id ;
if ( key === "OB_SETUP_1" || key === "OB_SETUP_2" ) {
var player_id, $sortable ;
if ( key === "OB_SETUPS_1" || key === "OB_SETUPS_2" ) {
player_id = key.substring( key.length-1 ) ;
var $sortable = $( "#ob_setup-sortable_" + player_id ) ;
$sortable = $( "#ob_setups-sortable_" + player_id ) ;
for ( i=0 ; i < params[key].length ; ++i )
do_add_ob_setup( $sortable, params[key][i] ) ;
params_loaded[key] = true ;
continue ;
}
if ( key === "OB_NOTES_1" || key === "OB_NOTES_2" ) {
player_id = key.substring( key.length-1 ) ;
$sortable = $( "#ob_notes-sortable_" + player_id ) ;
for ( i=0 ; i < params[key].length ; ++i )
do_add_ob_note( $sortable, params[key][i] ) ;
params_loaded[key] = true ;
continue ;
}
if ( key === "VEHICLES_1" || key === "ORDNANCE_1" || key === "VEHICLES_2" || key === "ORDNANCE_2" ) {
player_id = key.substring( key.length-1 ) ;
@ -562,7 +571,7 @@ function do_load_scenario( params )
function on_save_scenario()
{
// unload the template parameters
function unload_ob_setups( $sortable ) {
function unload_ob_entries( $sortable ) {
var entries = [] ;
$sortable.children("li").each( function() {
entries.push( $(this).data( "sortable-data" ) ) ;
@ -579,8 +588,10 @@ function on_save_scenario()
}
var params = {} ;
unload_params( params, false ) ;
params.OB_SETUP_1 = unload_ob_setups( $("#ob_setup-sortable_1") ) ;
params.OB_SETUP_2 = unload_ob_setups( $("#ob_setup-sortable_2") ) ;
params.OB_SETUPS_1 = unload_ob_entries( $("#ob_setups-sortable_1") ) ;
params.OB_SETUPS_2 = unload_ob_entries( $("#ob_setups-sortable_2") ) ;
params.OB_NOTES_1 = unload_ob_entries( $("#ob_notes-sortable_1") ) ;
params.OB_NOTES_2 = unload_ob_entries( $("#ob_notes-sortable_2") ) ;
extract_vo_names( "VEHICLES_1" ) ;
extract_vo_names( "ORDNANCE_1" ) ;
extract_vo_names( "VEHICLES_2" ) ;
@ -629,7 +640,8 @@ function on_new_scenario( verbose )
// reset all the template parameters
for ( var i=1 ; i <= 2 ; ++i ) {
delete_all_sortable_entries( $("#ob_setup-sortable_"+i) ) ;
delete_all_sortable_entries( $("#ob_setups-sortable_"+i) ) ;
delete_all_sortable_entries( $("#ob_notes-sortable_"+i) ) ;
delete_all_vo( "vehicle", i ) ;
delete_all_vo( "ordnance", i ) ;
}

@ -88,32 +88,39 @@
<div id="tabs-ob1">
<fieldset class="tl"> <legend>OB setup</legend>
<div id="panel-ob_setup1" class="panel-ob_setup">
<div id="panel-ob_setups1" class="panel-ob_setups">
<div class="content">
<div id="ob_setup-hint_1" class="ob_setup-hint"> <p>Click on the "+" below to add a new setup note. <p>To re-order the setup notes, use the mouse to drag them around. <p>Ctrl-click on a setup note to delete it, or drag it into the trashcan below. </div>
<ul id="ob_setup-sortable_1" class="sortable" style="display:none;"></ul>
<div id="ob_setups-hint_1" class="ob_setups-hint"> <p>Click on the "+" below to add a new setup note. <p>To re-order the setup notes, use the mouse to drag them around. <p>Ctrl-click on a setup note to delete it, or drag it into the trashcan below. </div>
<ul id="ob_setups-sortable_1" class="sortable" style="display:none;"></ul>
</div>
<div class="footer">
<div class="l">
<input type="button" id="ob_setup-add_1" value="+">
<img id="ob_setup-trash_1" class="ob_setup-trash" src="{{url_for('static',filename='images/trash.png')}}">
<input type="button" id="ob_setups-add_1" value="+">
<img id="ob_setups-trash_1" class="ob_setups-trash" src="{{url_for('static',filename='images/trash.png')}}">
</div>
<input type="button" data-id="ob_setup" value="EDIT TEMPLATE">
<input type="button" data-id="ob_setup" value="EDIT">
</div>
</div>
</fieldset>
<fieldset class="bl"> <legend>Notes</legend>
<div id="panel-ob_notes1" class="panel-ob_notes">
<div class="content">
<div id="ob_notes-hint_1" class="ob_notes-hint"> <p>Click on the "+" below to add a new setup note. <p>To re-order the setup notes, use the mouse to drag them around. <p>Ctrl-click on a setup note to delete it, or drag it into the trashcan below. </div>
<ul id="ob_notes-sortable_1" class="sortable" style="display:none;"></ul>
</div>
<div class="footer">
<input type="button" class="generate" data-id="mol" value="MOL">
<input type="button" class="generate" data-id="mol-p" value="MOL-P">
<input type="button" class="generate" data-id="pf" value="PF">
<input type="button" class="generate" data-id="psk" value="PSK">
<input type="button" class="generate" data-id="atmm" value="ATMM">
<input type="button" class="generate" data-id="baz" value="BAZ">
<input type="button" class="generate" data-id="piat" value="PIAT">
<div class="l">
<input type="button" id="ob_notes-add_1" value="+">
<img id="ob_notes-trash_1" class="ob_notes-trash" src="{{url_for('static',filename='images/trash.png')}}">
</div>
<input type="button" data-id="ob_note" value="EDIT">
<input type="button" class="generate" data-id="mol" value="MOL">
<input type="button" class="generate" data-id="mol-p" value="MOL-P">
<input type="button" class="generate" data-id="pf" value="PF">
<input type="button" class="generate" data-id="psk" value="PSK">
<input type="button" class="generate" data-id="atmm" value="ATMM">
<input type="button" class="generate" data-id="baz" value="BAZ">
<input type="button" class="generate" data-id="piat" value="PIAT">
</div>
</div>
</fieldset>
@ -165,7 +172,7 @@
<div id="edit-template" style="display:none;"> <textarea></textarea> </div>
<div id="edit-ssr" style="display:none;"> <b>Enter the SSR content:</b> <textarea></textarea> </div>
<div id="edit-ob_setup" style="display:none;">
<div id="edit-simple_note" style="display:none;">
<textarea></textarea>
<label>Width:</label> <input type="text" size="5">
</div>
@ -195,7 +202,7 @@ gOrdnanceListingsUrl = "{{url_for('get_ordnance_listings')}}" ;
<script src="{{url_for('static',filename='main.js')}}"></script>
<script src="{{url_for('static',filename='snippets.js')}}"></script>
<script src="{{url_for('static',filename='ssr.js')}}"></script>
<script src="{{url_for('static',filename='ob_setup.js')}}"></script>
<script src="{{url_for('static',filename='simple_notes.js')}}"></script>
<script src="{{url_for('static',filename='vehicles_ordnance.js')}}"></script>
<script src="{{url_for('static',filename='sortable.js')}}"></script>
<script src="{{url_for('static',filename='utils.js')}}"></script>

@ -0,0 +1 @@
[{{PLAYER_NAME}}] [{{OB_NOTE}}]{%if OB_NOTE_WIDTH%} (width=[{{OB_NOTE_WIDTH}}]){%endif%}

@ -1,5 +1,6 @@
""" Test generating OB SETUP snippets. """
import re
import types
from selenium.webdriver.support.ui import Select
@ -10,48 +11,67 @@ from vasl_templates.webapp.tests.utils import select_tab, find_child, find_child
# ---------------------------------------------------------------------
# NOTE: Handling of OB setups and OB notes is identical (the only difference
# is in the template files, where OB setups have a colored header).
def test_ob_setup( webapp, webdriver ):
"""Test generating OB SETUP snippets."""
"""Test generating OB setup snippets."""
_do_test_ob_entries( webapp, webdriver, "ob_setups" )
def test_ob_notes( webapp, webdriver ):
"""Test generating OB note snippets."""
_do_test_ob_entries( webapp, webdriver, "ob_notes" )
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
def _do_test_ob_entries( webapp, webdriver, ob_type ):
"""Test generating OB setup/notes."""
# initialize
webdriver.get( webapp.url_for( "main" ) )
colors = {
"german": "col=[OBCOL:german/OBCOL2:german]", #.format( ob_type ) ,
"russian": "col=[OBCOL:russian/OBCOL2:russian]" #.format( ob_type )
}
# generate OB SETUP snippets for both players
# generate OB setup/note snippets for both players
def check_snippet( player_id, entry_no, expected ):
"""Generate the snippet for an OB setup."""
"""Generate the snippet for an OB setup/note."""
select_tab( "ob{}".format( player_id ) )
elems = find_children( "#ob_setup-sortable_{} li input[type='button']".format( player_id ) )
elems = find_children( "#{}-sortable_{} li input[type='button']".format( ob_type, player_id ) )
elems[entry_no].click()
if ob_type == "ob_notes":
expected = re.sub( r" \(col=.*?\)", "", expected )
assert get_clipboard() == expected
add_ob_setup( webdriver, 1, "ob setup #1" )
add_ob_setup( webdriver, 1, "ob setup #2", "2px" )
add_ob_setup( webdriver, 2, "ob <i>setup</i> #3", "3px" )
check_snippet( 1, 0, "[German] [ob setup #1] (col=[OBCOL:german/OBCOL2:german])" )
check_snippet( 1, 1, "[German] [ob setup #2] (col=[OBCOL:german/OBCOL2:german]) (width=[2px])" )
check_snippet( 2, 0, "[Russian] [ob <i>setup</i> #3] (col=[OBCOL:russian/OBCOL2:russian]) (width=[3px])" )
_do_add_ob_entry( webdriver, 1, ob_type, "{} #1".format(ob_type), None )
_do_add_ob_entry( webdriver, 1, ob_type, "{} #2".format(ob_type), "2px" )
_do_add_ob_entry( webdriver, 2, ob_type, "<i>{}</i> #3".format(ob_type), "3px" )
check_snippet( 1, 0, "[German] [{} #1] ({})".format( ob_type, colors["german"] ) )
check_snippet( 1, 1, "[German] [{} #2] ({}) (width=[2px])".format( ob_type, colors["german"] ) )
check_snippet( 2, 0, "[Russian] [<i>{}</i> #3] ({}) (width=[3px])".format( ob_type, colors["russian"] ) )
# make some changes and check the snippets again
edit_ob_setup( webdriver, 2, 0, "updated ob setup #3", "" )
edit_ob_setup( webdriver, 1, 1, "<i>updated ob setup #2</i>", "200px" )
edit_ob_setup( webdriver, 1, 0, None, "100px" )
check_snippet( 2, 0, "[Russian] [updated ob setup #3] (col=[OBCOL:russian/OBCOL2:russian])" )
check_snippet( 1, 1, "[German] [<i>updated ob setup #2</i>] (col=[OBCOL:german/OBCOL2:german]) (width=[200px])" )
check_snippet( 1, 0, "[German] [ob setup #1] (col=[OBCOL:german/OBCOL2:german]) (width=[100px])" )
# delete an OB setup by dragging it into the trash
_do_edit_ob_entry( webdriver, 2, ob_type, 0, "updated {} #3".format(ob_type), "" )
_do_edit_ob_entry( webdriver, 1, ob_type, 1, "<i>updated {} #2</i>".format(ob_type), "200px" )
_do_edit_ob_entry( webdriver, 1, ob_type, 0, None, "100px" )
check_snippet( 2, 0, "[Russian] [updated {} #3] ({})".format( ob_type, colors["russian"] ) )
check_snippet( 1, 1, "[German] [<i>updated {} #2</i>] ({}) (width=[200px])".format( ob_type, colors["german"] ) )
check_snippet( 1, 0, "[German] [{} #1] ({}) (width=[100px])".format( ob_type, colors["german"] ) )
# delete an OB setup/note by dragging it into the trash
def count_entries( player_id ):
"""Count the number of OB setup's."""
elems = find_children( "#ob_setup-sortable_{} li".format( player_id ) )
"""Count the number of OB setup/notes."""
elems = find_children( "#{}-sortable_{} li".format( ob_type, player_id ) )
return len(elems)
select_tab( "ob1" )
assert count_entries(1) == 2
elem = find_child( "#ob_setup-sortable_1 li[2]" )
trash = find_child( "#ob_setup-trash_1" )
elem = find_child( "#{}-sortable_1 li[2]".format( ob_type ) )
trash = find_child( "#{}-trash_1".format( ob_type ) )
ActionChains(webdriver).drag_and_drop( elem, trash ).perform()
assert count_entries(1) == 1
# delete an OB setup by emptying its caption
edit_ob_setup( webdriver, 1, 0, "", None )
# delete an OB setup/note by emptying its caption
_do_edit_ob_entry( webdriver, 1, ob_type, 0, "", None )
click_dialog_button( "OK" ) # nb: confirm the deletion
assert count_entries(1) == 0
@ -167,32 +187,47 @@ def test_nationality_specific( webapp, webdriver ):
# ---------------------------------------------------------------------
def add_ob_setup( webdriver, player_id, caption, width=None ):
def add_ob_setup( webdriver, player_id, caption, width ):
"""Add a new OB setup."""
_do_add_ob_entry( webdriver, player_id, "ob_setups", caption, width )
def add_ob_note( webdriver, player_id, caption, width ):
"""Add a new OB note."""
_do_add_ob_entry( webdriver, player_id, "ob_notes", caption, width )
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
def _do_add_ob_entry( webdriver, player_id, ob_type, caption, width ):
"""Add a new OB setup/note."""
select_tab( "ob{}".format( player_id ) )
elem = find_child( "#ob_setup-add_{}".format( player_id ) )
elem = find_child( "#{}-add_{}".format( ob_type, player_id ) )
elem.click()
edit_ob_setup( webdriver, player_id, None, caption, width )
_do_edit_ob_entry( webdriver, player_id, ob_type, None, caption, width )
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# ---------------------------------------------------------------------
def edit_ob_setup( webdriver, player_id, entry_no, caption, width ):
"""Edit an OB setup."""
_do_edit_ob_entry( webdriver, player_id, "ob_setups", entry_no, caption, width )
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
def _do_edit_ob_entry( webdriver, player_id, ob_type, entry_no, caption, width ):
"""Edit an OB setup/note."""
# locate the requested entry and start editing it
if entry_no is not None:
select_tab( "ob{}".format( player_id ) )
elems = find_children( "#ob_setup-sortable_{} li".format( player_id ) )
elems = find_children( "#{}-sortable_{} li".format( ob_type, player_id ) )
elem = elems[ entry_no ]
ActionChains(webdriver).double_click( elem ).perform()
# edit the OB setup
# edit the OB setup/note
if caption is not None:
elem = find_child( "#edit-ob_setup textarea" )
elem = find_child( "#edit-simple_note textarea" )
elem.clear()
elem.send_keys( caption )
if width is not None:
elem = find_child( "#edit-ob_setup input[type='text']" )
elem = find_child( "#edit-simple_note input[type='text']" )
elem.clear()
elem.send_keys( width )
click_dialog_button( "OK" )

@ -34,14 +34,22 @@ def test_scenario_persistence( webapp, webdriver ):
"SSR_WIDTH": "103",
},
"ob1": {
"OB_SETUP_1": [ { "caption": "ob setup 1a", "width": "" }, { "caption": "ob setup 1b", "width": "200px" } ],
"OB_SETUPS_1": [
{ "caption": "ob setup 1a", "width": "" },
{ "caption": "ob setup 1b", "width": "200px" }
],
"OB_NOTES_1": [
{ "caption": "ob note 1a", "width": "10em" },
{ "caption": "ob note 1b", "width": "" }
],
"VEHICLES_1": [ "a russian vehicle", "another russian vehicle" ],
"VEHICLES_WIDTH_1": "202",
"ORDNANCE_1": [ "a russian ordnance", "another russian ordnance" ],
"ORDNANCE_WIDTH_1": "203",
},
"ob2": {
"OB_SETUP_2": [ { "caption": "ob setup 2", "width": "" } ],
"OB_SETUPS_2": [ { "caption": "ob setup 2", "width": "" } ],
"OB_NOTES_2": [ { "caption": "ob note 2", "width": "" } ],
"VEHICLES_2": [ "a german vehicle" ],
"VEHICLES_WIDTH_2": "302",
"ORDNANCE_2": [ "a german ordnance" ],
@ -77,7 +85,9 @@ def test_scenario_persistence( webapp, webdriver ):
for field,val in scenario_params[tab_id].items():
if field == "SSR":
continue # nb: this requires special handling, we do it below
if field in ("OB_SETUP_1","OB_SETUP_2"):
if field in ("OB_SETUPS_1","OB_SETUPS_2"):
continue # nb: this requires special handling, we do it below
if field in ("OB_NOTES_1","OB_NOTES_2"):
continue # nb: this requires special handling, we do it below
if field in ("VEHICLES_1","ORDNANCE_1","VEHICLES_2","ORDNANCE_2"):
continue # nb: this requires special handling, we do it below
@ -91,8 +101,10 @@ def test_scenario_persistence( webapp, webdriver ):
assert elem.get_attribute("value") == val
ssrs = _get_ssrs()
assert ssrs == scenario_params["scenario"]["SSR"]
assert _get_ob_setups(1) == [ obs["caption"] for obs in scenario_params["ob1"]["OB_SETUP_1"] ]
assert _get_ob_setups(2) == [ obs["caption"] for obs in scenario_params["ob2"]["OB_SETUP_2"] ]
assert _get_ob_entries("ob_setups",1) == [ obs["caption"] for obs in scenario_params["ob1"]["OB_SETUPS_1"] ]
assert _get_ob_entries("ob_setups",2) == [ obs["caption"] for obs in scenario_params["ob2"]["OB_SETUPS_2"] ]
assert _get_ob_entries("ob_notes",1) == [ obs["caption"] for obs in scenario_params["ob1"]["OB_NOTES_1"] ]
assert _get_ob_entries("ob_notes",2) == [ obs["caption"] for obs in scenario_params["ob2"]["OB_NOTES_2"] ]
assert _get_vo("vehicle",1) == scenario_params["ob1"]["VEHICLES_1"]
assert _get_vo("ordnance",1) == scenario_params["ob1"]["ORDNANCE_1"]
assert _get_vo("vehicle",2) == scenario_params["ob2"]["VEHICLES_2"]
@ -164,12 +176,12 @@ def _get_ssrs():
select_tab( "scenario" )
return [ c.text for c in find_children("#ssr-sortable li") ]
def _get_ob_setups( player_id ):
"""Get the OB setup's from the UI."""
def _get_ob_entries( ob_type, player_id ):
"""Get the OB setup/notes from the UI."""
select_tab( "ob{}".format( player_id ) )
return [
c.text
for c in find_children( "#ob_setup-sortable_{} li".format( player_id ) )
for c in find_children( "#{}-sortable_{} li".format( ob_type, player_id ) )
]
def _get_vo( vo_type, player_id ):

@ -2,6 +2,7 @@
from selenium.webdriver.common.keys import Keys
from vasl_templates.webapp.tests.test_ob import add_ob_setup, add_ob_note
from vasl_templates.webapp.tests.utils import select_tab, set_template_params, get_clipboard
from vasl_templates.webapp.tests.utils import get_stored_msg, dismiss_notifications, find_child
from vasl_templates.webapp.tests.utils import for_each_template, wait_for
@ -171,8 +172,8 @@ def test_edit_templates( webapp, webdriver ):
elem.send_keys( Keys.ESCAPE )
def test_template( template_id, orig_template_id ):
"""Test editing a template."""
if template_id == "ob_setup":
return # nb: this requires special handling (done below)
if template_id in("ob_setup","ob_note"):
return # nb: these require special handling (done below)
# edit the template
elem = find_child( "a.edit-template-link[data-id='{}']".format( template_id ) )
webdriver.execute_script( "$(arguments[0]).click();", elem )
@ -181,21 +182,33 @@ def test_edit_templates( webapp, webdriver ):
dismiss_notifications()
elem = find_child( "input.generate[data-id='{}']".format( orig_template_id ) )
elem.click()
wait_for( 2, # FUDGE! Work-around a weird timing problem on Linux :shrug:
wait_for( 5, # FUDGE! Work-around a weird timing problem on Linux :shrug:
lambda: get_clipboard() == "EDITED TEMPLATE: {}".format( orig_template_id )
)
for_each_template( test_template )
# customize the OB SETUP template
select_tab( "ob2" )
elem = find_child( "#tabs-ob2 input[type='button'][data-id='ob_setup']" )
select_tab( "ob1" )
elem = find_child( "#tabs-ob1 input[type='button'][data-id='ob_setup']" )
elem.click()
edit_template( "ob_setup" )
# check that the new template is being used
from vasl_templates.webapp.tests.test_ob_setup import add_ob_setup
for player_id in range(1,2+1):
add_ob_setup( webdriver, player_id, "ob setup (ignored)" )
elem = find_child( "#ob_setup-sortable_{} li input[type='button']".format( player_id ) )
add_ob_setup( webdriver, player_id, "ob setup (ignored)", None )
elem = find_child( "#ob_setups-sortable_{} li input[type='button']".format( player_id ) )
elem.click()
assert get_clipboard() == "EDITED TEMPLATE: ob_setup"
# customize the OB NOTE template
select_tab( "ob2" )
elem = find_child( "#tabs-ob2 input[type='button'][data-id='ob_note']" )
elem.click()
edit_template( "ob_note" )
# check that the new template is being used
for player_id in range(1,2+1):
add_ob_note( webdriver, player_id, "ob note (ignored)", None )
elem = find_child( "#ob_notes-sortable_{} li input[type='button']".format( player_id ) )
elem.click()
assert get_clipboard() == "EDITED TEMPLATE: ob_note"

@ -8,7 +8,7 @@ import base64
from selenium.webdriver.support.ui import Select
from vasl_templates.webapp import snippets
from vasl_templates.webapp.tests.test_ob_setup import add_ob_setup
from vasl_templates.webapp.tests import test_ob
from vasl_templates.webapp.tests.utils import select_tab, select_menu_option, dismiss_notifications
from vasl_templates.webapp.tests.utils import get_clipboard, get_stored_msg, set_stored_msg
from vasl_templates.webapp.tests.utils import for_each_template, find_child, find_children
@ -26,10 +26,11 @@ def test_individual_files( webapp, webdriver ):
"""Test uploading a customized version of the template."""
# make sure generating a snippet returns something
dismiss_notifications()
if template_id == "ob_setup":
if template_id in ("ob_setup","ob_note"):
select_tab( "ob1" )
add_ob_setup( webdriver, 1, "test ob setup" )
elems = find_children( "#ob_setup-sortable_1 li input[type='button']" )
func = getattr( test_ob, "add_"+template_id )
func( webdriver, 1, "test {}".format(template_id), None )
elems = find_children( "#{}s-sortable_1 li input[type='button']".format( template_id ) )
elem = elems[0]
else:
elem = find_child( "input.generate[data-id='{}']".format( orig_template_id ) )
@ -149,21 +150,22 @@ def test_nationality_data( webapp, webdriver ):
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
def _check_snippets( webdriver, func ):
def _check_snippets( webdriver, expected ):
"""Check that snippets are being generated as expected."""
def test_template( template_id, orig_template_id ):
"""Test each template."""
dismiss_notifications()
if template_id == "ob_setup":
if template_id in ("ob_setup","ob_note"):
select_tab( "ob1" )
add_ob_setup( webdriver, 1, "test ob setup" )
elems = find_children( "#ob_setup-sortable_1 li input[type='button']" )
func = getattr( test_ob, "add_"+template_id )
func( webdriver, 1, "test {}".format(template_id), None )
elems = find_children( "#{}s-sortable_1 li input[type='button']".format( template_id ) )
elem = elems[0]
else:
elem = find_child( "input.generate[data-id='{}']".format( orig_template_id ) )
elem.click()
assert get_clipboard() == func( template_id )
assert get_clipboard() == expected( template_id )
for_each_template( test_template )
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

@ -13,8 +13,8 @@ from selenium.common.exceptions import NoSuchElementException, StaleElementRefer
# standard templates
_STD_TEMPLATES = {
"scenario": [ "scenario", "players", "victory_conditions", "ssr" ],
"ob1": [ "ob_setup_1", "vehicles_1", "ordnance_1" ],
"ob2": [ "ob_setup_2", "vehicles_2", "ordnance_2" ],
"ob1": [ "ob_setup_1", "ob_note_1", "vehicles_1", "ordnance_1" ],
"ob2": [ "ob_setup_2", "ob_note_2", "vehicles_2", "ordnance_2" ],
}
# nationality-specific templates
@ -47,6 +47,8 @@ def for_each_template( func ):
select_tab( tab_id )
if template_id.startswith( "ob_setup_" ):
template_id2 = "ob_setup"
elif template_id.startswith( "ob_note_" ):
template_id2 = "ob_note"
elif template_id.startswith( "vehicles_" ):
template_id2 = "vehicles"
elif template_id.startswith( "ordnance_" ):
@ -54,7 +56,7 @@ def for_each_template( func ):
else:
template_id2 = template_id
func( template_id2, template_id )
if template_id not in ("ob_setup_2","vehicles_2","ordnance_2"):
if template_id not in ("ob_setup_2","ob_note_2","vehicles_2","ordnance_2"):
templates_to_test.remove( template_id2 )
# test the nationality-specific templates
@ -88,7 +90,7 @@ def select_menu_option( menu_id ):
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
def set_template_params( params ):
def set_template_params( params ): #pylint: disable=too-many-branches
"""Set template parameters."""
for key,val in params.items():
@ -101,15 +103,24 @@ def set_template_params( params ):
add_ssr( _webdriver, ssr )
continue
# check for OB set up (these require special handling)
if key in ("OB_SETUP_1","OB_SETUP_2"):
# check for OB setups (these require special handling)
if key in ("OB_SETUPS_1","OB_SETUPS_2"):
# add them in (nb: we don't consider any existing OB setup's)
from vasl_templates.webapp.tests.test_ob_setup import add_ob_setup #pylint: disable=cyclic-import
from vasl_templates.webapp.tests.test_ob import add_ob_setup #pylint: disable=cyclic-import
player_id = int( key[-1] )
for entry in val:
add_ob_setup( _webdriver, player_id, entry.get("caption",""), entry.get("width","") )
continue
# check for OB notes (these require special handling)
if key in ("OB_NOTES_1","OB_NOTES_2"):
from vasl_templates.webapp.tests.test_ob import add_ob_note #pylint: disable=cyclic-import
# add them in (nb: we don't consider any existing OB notes)
player_id = int( key[-1] )
for entry in val:
add_ob_note( _webdriver, player_id, entry.get("caption",""), entry.get("width","") )
continue
# check for vehicles/ordnance (these require special handling)
if key in ("VEHICLES_1","ORDNANCE_1","VEHICLES_2","ORDNANCE_2"):
# add them in (nb: we don't consider any existing vehicles/ordnance)

Loading…
Cancel
Save