Added support for Chapter H vehicle/ordnance notes and multi-applicable notes.

master
Pacman Ghost 5 years ago
parent ed962b0456
commit fbdcd70710
  1. 2
      Dockerfile
  2. 7
      conftest.py
  3. 1
      docker/config/site.cfg
  4. 1
      vasl_templates/webapp/__init__.py
  5. 2
      vasl_templates/webapp/config/site.cfg.example
  6. 5
      vasl_templates/webapp/data/default-scenario.json
  7. 34
      vasl_templates/webapp/data/default-template-pack/nationalities.json
  8. 43
      vasl_templates/webapp/data/default-template-pack/ob_ordnance_ma_notes.j2
  9. 23
      vasl_templates/webapp/data/default-template-pack/ob_ordnance_note.j2
  10. 23
      vasl_templates/webapp/data/default-template-pack/ob_vehicle_note.j2
  11. 43
      vasl_templates/webapp/data/default-template-pack/ob_vehicles_ma_notes.j2
  12. 2
      vasl_templates/webapp/data/ordnance/chinese.json
  13. 21
      vasl_templates/webapp/files.py
  14. 2
      vasl_templates/webapp/static/css/sortable.css
  15. 21
      vasl_templates/webapp/static/css/tabs-ob.css
  16. 2
      vasl_templates/webapp/static/css/tabs.css
  17. 35
      vasl_templates/webapp/static/main.js
  18. 4
      vasl_templates/webapp/static/simple_notes.js
  19. 288
      vasl_templates/webapp/static/snippets.js
  20. 64
      vasl_templates/webapp/static/vassal.js
  21. 46
      vasl_templates/webapp/static/vo.js
  22. 2
      vasl_templates/webapp/templates/index.html
  23. 42
      vasl_templates/webapp/templates/tabs-ob1.html
  24. 182
      vasl_templates/webapp/templates/vo-notes-report.html
  25. 2
      vasl_templates/webapp/templates/vo-report.html
  26. 2
      vasl_templates/webapp/testing.py
  27. 12
      vasl_templates/webapp/tests/fixtures/data/default-template-pack/nationalities.json
  28. 8
      vasl_templates/webapp/tests/fixtures/data/default-template-pack/ob_ordnance_ma_notes.j2
  29. 1
      vasl_templates/webapp/tests/fixtures/data/default-template-pack/ob_ordnance_note.j2
  30. 1
      vasl_templates/webapp/tests/fixtures/data/default-template-pack/ob_vehicle_note.j2
  31. 8
      vasl_templates/webapp/tests/fixtures/data/default-template-pack/ob_vehicles_ma_notes.j2
  32. 9
      vasl_templates/webapp/tests/fixtures/data/ordnance/allied-minor/common.json
  33. 9
      vasl_templates/webapp/tests/fixtures/data/ordnance/allied-minor/dutch.json
  34. 9
      vasl_templates/webapp/tests/fixtures/data/ordnance/axis-minor/common.json
  35. 9
      vasl_templates/webapp/tests/fixtures/data/ordnance/axis-minor/romanian.json
  36. 12
      vasl_templates/webapp/tests/fixtures/data/ordnance/italian.json
  37. 1
      vasl_templates/webapp/tests/fixtures/data/ordnance/russian.json
  38. 9
      vasl_templates/webapp/tests/fixtures/data/vehicles/allied-minor/common.json
  39. 10
      vasl_templates/webapp/tests/fixtures/data/vehicles/allied-minor/dutch.json
  40. 9
      vasl_templates/webapp/tests/fixtures/data/vehicles/axis-minor/common.json
  41. 10
      vasl_templates/webapp/tests/fixtures/data/vehicles/axis-minor/romanian.json
  42. 2
      vasl_templates/webapp/tests/fixtures/data/vehicles/british.json
  43. 9
      vasl_templates/webapp/tests/fixtures/data/vehicles/german.json
  44. 12
      vasl_templates/webapp/tests/fixtures/data/vehicles/italian.json
  45. 8
      vasl_templates/webapp/tests/fixtures/data/vehicles/japanese.json
  46. 14
      vasl_templates/webapp/tests/fixtures/data/vehicles/landing-craft.json
  47. 1
      vasl_templates/webapp/tests/fixtures/data/vehicles/russian.json
  48. 1
      vasl_templates/webapp/tests/fixtures/file-server/1.txt
  49. 1
      vasl_templates/webapp/tests/fixtures/file-server/subdir/2.txt
  50. 1
      vasl_templates/webapp/tests/fixtures/template-packs/full/ob_ordnance_ma_notes.j2
  51. 1
      vasl_templates/webapp/tests/fixtures/template-packs/full/ob_ordnance_note.j2
  52. 1
      vasl_templates/webapp/tests/fixtures/template-packs/full/ob_vehicle_note.j2
  53. 1
      vasl_templates/webapp/tests/fixtures/template-packs/full/ob_vehicles_ma_notes.j2
  54. 1
      vasl_templates/webapp/tests/fixtures/template-packs/new-default/ob_ordnance_ma_notes.j2
  55. 1
      vasl_templates/webapp/tests/fixtures/template-packs/new-default/ob_ordnance_note.j2
  56. 1
      vasl_templates/webapp/tests/fixtures/template-packs/new-default/ob_vehicle_note.j2
  57. 1
      vasl_templates/webapp/tests/fixtures/template-packs/new-default/ob_vehicles_ma_notes.j2
  58. 1
      vasl_templates/webapp/tests/fixtures/update-vsav/full-updated.json
  59. BIN
      vasl_templates/webapp/tests/fixtures/vo-notes/allied-minor/ordnance/102.png
  60. 1
      vasl_templates/webapp/tests/fixtures/vo-notes/allied-minor/ordnance/a.html
  61. 1
      vasl_templates/webapp/tests/fixtures/vo-notes/allied-minor/ordnance/du.html
  62. BIN
      vasl_templates/webapp/tests/fixtures/vo-notes/allied-minor/vehicles/101.png
  63. 1
      vasl_templates/webapp/tests/fixtures/vo-notes/allied-minor/vehicles/a.html
  64. 1
      vasl_templates/webapp/tests/fixtures/vo-notes/allied-minor/vehicles/du.html
  65. 1
      vasl_templates/webapp/tests/fixtures/vo-notes/american/vehicles/a.html
  66. BIN
      vasl_templates/webapp/tests/fixtures/vo-notes/axis-minor/ordnance/104.png
  67. 1
      vasl_templates/webapp/tests/fixtures/vo-notes/axis-minor/ordnance/a.html
  68. 1
      vasl_templates/webapp/tests/fixtures/vo-notes/axis-minor/ordnance/ro.html
  69. BIN
      vasl_templates/webapp/tests/fixtures/vo-notes/axis-minor/vehicles/103.png
  70. 1
      vasl_templates/webapp/tests/fixtures/vo-notes/axis-minor/vehicles/a.html
  71. 1
      vasl_templates/webapp/tests/fixtures/vo-notes/axis-minor/vehicles/ro.html
  72. 1
      vasl_templates/webapp/tests/fixtures/vo-notes/british/vehicles/a.html
  73. BIN
      vasl_templates/webapp/tests/fixtures/vo-notes/dutch/ordnance/2.png
  74. 1
      vasl_templates/webapp/tests/fixtures/vo-notes/dutch/ordnance/a.html
  75. BIN
      vasl_templates/webapp/tests/fixtures/vo-notes/dutch/vehicles/1.png
  76. 1
      vasl_templates/webapp/tests/fixtures/vo-notes/dutch/vehicles/a.html
  77. 1
      vasl_templates/webapp/tests/fixtures/vo-notes/french/ordnance/a.html
  78. BIN
      vasl_templates/webapp/tests/fixtures/vo-notes/german/ordnance/1.png
  79. BIN
      vasl_templates/webapp/tests/fixtures/vo-notes/german/ordnance/6.png
  80. BIN
      vasl_templates/webapp/tests/fixtures/vo-notes/german/ordnance/8.png
  81. 1
      vasl_templates/webapp/tests/fixtures/vo-notes/german/ordnance/a.html
  82. 1
      vasl_templates/webapp/tests/fixtures/vo-notes/german/ordnance/b.html
  83. BIN
      vasl_templates/webapp/tests/fixtures/vo-notes/german/vehicles/1.png
  84. 1
      vasl_templates/webapp/tests/fixtures/vo-notes/german/vehicles/a.html
  85. 1
      vasl_templates/webapp/tests/fixtures/vo-notes/german/vehicles/b.html
  86. 1
      vasl_templates/webapp/tests/fixtures/vo-notes/german/vehicles/b_.html
  87. 1
      vasl_templates/webapp/tests/fixtures/vo-notes/german/vehicles/c.html
  88. 1
      vasl_templates/webapp/tests/fixtures/vo-notes/italian/ordnance/r.html
  89. 1
      vasl_templates/webapp/tests/fixtures/vo-notes/italian/vehicles/r.html
  90. 1
      vasl_templates/webapp/tests/fixtures/vo-notes/japanese/vehicles/a.html
  91. 1
      vasl_templates/webapp/tests/fixtures/vo-notes/landing-craft/a.html
  92. 1
      vasl_templates/webapp/tests/fixtures/vo-notes/landing-craft/b.html
  93. BIN
      vasl_templates/webapp/tests/fixtures/vo-notes/romanian/ordnance/4.png
  94. 1
      vasl_templates/webapp/tests/fixtures/vo-notes/romanian/ordnance/a.html
  95. BIN
      vasl_templates/webapp/tests/fixtures/vo-notes/romanian/vehicles/3.png
  96. 1
      vasl_templates/webapp/tests/fixtures/vo-notes/romanian/vehicles/a.html
  97. BIN
      vasl_templates/webapp/tests/fixtures/vo-notes/russian/ordnance/1.png
  98. 1
      vasl_templates/webapp/tests/fixtures/vo-notes/russian/ordnance/x.html
  99. 1
      vasl_templates/webapp/tests/fixtures/vo-notes/russian/ordnance/y.html
  100. 1
      vasl_templates/webapp/tests/fixtures/vo-notes/russian/ordnance/zz.html
  101. Some files were not shown because too many files have changed in this diff Show More

@ -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

@ -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

@ -3,3 +3,4 @@
FLASK_HOST = 0.0.0.0
VASL_MOD = /data/vasl.vmod
CHAPTER_H_NOTES = /data/chapter-h-notes/

@ -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

@ -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...

@ -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"
}

@ -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"
}
}

@ -0,0 +1,43 @@
<html> <!-- vasl-templates:id {{SNIPPET_ID}} -->
<head>
<meta charset="utf-8">
<style>
.ma-note .key { font-weight: bold ; }
.extra-notes-caption { border: 1px solid #e0e0e0 ; background: #fcfcfc ; font-weight: bold ; padding: 2px 5px ; }
ul { margin: 0 0 0 15px ; padding: 0 ; }
sup { font-size: 75% ; }
</style>
</head>
<table style="
{%if OB_ORDNANCE_MA_NOTES_WIDTH%} width: {{OB_ORDNANCE_MA_NOTES_WIDTH}} ; {%endif%}
">
<tr>
<td colspan="2" style="
background: {{OB_COLOR}} ;
border-bottom: 1px solid {{OB_COLOR_2}} ;
padding: 2px 5px ;
font-weight: bold ;
">
{%if PLAYER_FLAG%}<img src="{{PLAYER_FLAG}}?height=11">&nbsp;{%endif%}{{PLAYER_NAME}} Ordnance Notes
{%if OB_ORDNANCE_MA_NOTES%}
<tr> <td style="padding: 0 5px;">
{%for ma_note in OB_ORDNANCE_MA_NOTES%}
<div class="ma-note"> {{ma_note}} </div>
{%endfor%}
{%endif%}
{%if OB_ORDNANCE_EXTRA_MA_NOTES%}
<tr> <td style="padding: 0 5px;">
{%if OB_ORDNANCE_EXTRA_MA_NOTES_CAPTION%} <div class="extra-notes-caption"> {{OB_ORDNANCE_EXTRA_MA_NOTES_CAPTION}} </div> {%endif%}
{%for ma_note in OB_ORDNANCE_EXTRA_MA_NOTES%}
<div class="ma-note"> {{ma_note}} </div>
{%endfor%}
{%endif%}
</table>
</html>

@ -0,0 +1,23 @@
<html> <!-- vasl-templates:id {{SNIPPET_ID}} -->
<head>
<meta charset="utf-8">
</head>
<table>
<tr>
<td colspan="2" style="
background: {{OB_COLOR}} ;
border-bottom: 1px solid {{OB_COLOR_2}} ;
padding: 2px 5px ;
font-weight: bold ;
">
{%if PLAYER_FLAG%}<img src="{{PLAYER_FLAG}}?height=11">&nbsp;{%endif%}{{ORDNANCE_NAME}}
<tr>
<td> <img src="{{ORDNANCE_NOTE_URL}}">
</table>
</html>

@ -0,0 +1,23 @@
<html> <!-- vasl-templates:id {{SNIPPET_ID}} -->
<head>
<meta charset="utf-8">
</head>
<table>
<tr>
<td colspan="2" style="
background: {{OB_COLOR}} ;
border-bottom: 1px solid {{OB_COLOR_2}} ;
padding: 2px 5px ;
font-weight: bold ;
">
{%if PLAYER_FLAG%}<img src="{{PLAYER_FLAG}}?height=11">&nbsp;{%endif%}{{VEHICLE_NAME}}
<tr>
<td> <img src="{{VEHICLE_NOTE_URL}}">
</table>
</html>

@ -0,0 +1,43 @@
<html> <!-- vasl-templates:id {{SNIPPET_ID}} -->
<head>
<meta charset="utf-8">
<style>
.ma-note .key { font-weight: bold ; }
.extra-notes-caption { border: 1px solid #e0e0e0 ; background: #fcfcfc ; font-weight: bold ; padding: 2px 5px ; }
ul { margin: 0 0 0 15px ; padding: 0 ; }
sup { font-size: 75% ; }
</style>
</head>
<table style="
{%if OB_VEHICLES_MA_NOTES_WIDTH%} width: {{OB_VEHICLES_MA_NOTES_WIDTH}} ; {%endif%}
">
<tr>
<td colspan="2" style="
background: {{OB_COLOR}} ;
border-bottom: 1px solid {{OB_COLOR_2}} ;
padding: 2px 5px ;
font-weight: bold ;
">
{%if PLAYER_FLAG%}<img src="{{PLAYER_FLAG}}?height=11">&nbsp;{%endif%}{{PLAYER_NAME}} Vehicle Notes
{%if OB_VEHICLES_MA_NOTES%}
<tr> <td style="padding: 0 5px;">
{%for ma_note in OB_VEHICLES_MA_NOTES%}
<div class="ma-note"> {{ma_note}} </div>
{%endfor%}
{%endif%}
{%if OB_VEHICLES_EXTRA_MA_NOTES%}
<tr> <td style="padding: 0 5px;">
{%if OB_VEHICLES_EXTRA_MA_NOTES_CAPTION%} <div class="extra-notes-caption"> {{OB_VEHICLES_EXTRA_MA_NOTES_CAPTION}} </div> {%endif%}
{%for ma_note in OB_VEHICLES_EXTRA_MA_NOTES%}
<div class="ma-note"> {{ma_note}} </div>
{%endfor%}
{%endif%}
</table>
</html>

@ -167,7 +167,7 @@
"capabilities": [ "NT", "QSU", "h-d" ],
"capabilities2": { "WP": 7, "C": "5\u2020<sup>1</sup>" },
"note_number": "10\u2020",
"notes": [ "A", "C \u2020<sup>1</sup>" ],
"notes": [ "A", "C\u2020<sup>1</sup>" ],
"id": "ch/o:019",
"gpid": 2037
},

@ -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

@ -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 ; }

@ -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 ; }

@ -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 }

@ -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:<div class='pre'>" + escapeHTML(errorMsg) + "</div>" ) ;
} ) ;
$.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:<div class='pre'>" + escapeHTML(errorMsg) + "</div>" ) ;
} ) ;
$.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:<div class='pre'>" + escapeHTML(errorMsg) + "</div>" ) ;
} ) ;
// 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( "" ) ;

@ -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(
"<img src='" + gImagesBaseUrl + "/snippet.png" + "'",
"<img src='" + gImagesBaseUrl + "/snippet.png'",
" class='snippet' data-id='" + note_type0 + "' title='Generate a snippet.'>"
) ;
}

@ -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(
"<span class='key'>" +
(nat === "italian" && vo_type === "ordnance" && keys[i] === "R" ? "<s>R</s>" : keys[i]) + ":" +
"</span> " +
(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])<sup>" ),
new RegExp( "^<s>([A-Za-z])</s>$" ),
] ;
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<sup>" + no_if.substring(0,no_if.length-1) + "</sup>\u2020" ;
else
no_if = "no IF<sup>" + no_if + "</sup>" ;
@ -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 == "<invalid>" ) {
if ( cap === "<invalid>" ) {
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 ) {

@ -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 ;
}

@ -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 = "<div class='vo-entry" ;
var fixed_height = "3.25em" ;
@ -143,18 +149,48 @@ function do_add_vo( vo_type, player_no, vo_entry, vo_image_id, custom_capabiliti
} ;
if ( custom_capabilities )
data.custom_capabilities = custom_capabilities ;
data.id = seq_id ;
var buf = [ div_tag,
"<img class='vasl-image'>",
"<div class='detail'>",
"<div class='vo-name'></div>",
"<div class='vo-capabilities'></div>",
"</div>",
"</div>" ] ;
"</div>"
] ;
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(
"<img src='" + gImagesBaseUrl + "/snippet.png'",
" class='snippet' data-id='" + template_id + "' title='Generate a snippet.'>"
) ;
data.vo_note_url = APP_URL_BASE + "/" + vo_type + "/" + vo_nat + "/note/" + vo_note_key ;
}
buf.push( "</div>" ) ;
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 )

@ -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')}}" ;

@ -52,13 +52,24 @@
<ul id="ob_vehicles-sortable_1" class="sortable" style="display:none;"></ul>
</div>
<div class="footer">
<button id="ob_vehicles-add_1" class="sortable-add"></button>
<img id="ob_vehicles-trash_1" class="sortable-trash">
<div class="snippet-admin">
<button id="ob_vehicles-add_1" class="sortable-add"></button>
<img id="ob_vehicles-trash_1" class="sortable-trash">
</div>
<span class="spacer"></span>
<span class="small">
<label for="OB_VEHICLES_WIDTH_1">Width:</label>
<input type="text" class="param" name="OB_VEHICLES_WIDTH_1" size="5">
<button class="generate" data-id="ob_vehicles_1">Snippet</button>
<div class="snippets-ob">
<label for="ob" class="header">OB:</label>
<label for="OB_VEHICLES_WIDTH_1">Width:</label>
<input type="text" class="param" name="OB_VEHICLES_WIDTH_1" size="5">
<button class="generate" data-id="ob_vehicles_1">Snippet</button>
</div>
<div class="snippets-notes">
<label class="header">Notes:</label>
<label for="OB_VEHICLES_MA_NOTES_WIDTH_1">Width:</label>
<input type="text" class="param" name="OB_VEHICLES_MA_NOTES_WIDTH_1" size="5">
<button class="generate" data-id="ob_vehicles_ma_notes_1">Snippet</button>
</div>
</span>
</div>
</div>
@ -71,13 +82,24 @@
<ul id="ob_ordnance-sortable_1" class="sortable" style="display:none;"></ul>
</div>
<div class="footer">
<button id="ob_ordnance-add_1" class="sortable-add"></button>
<img id="ob_ordnance-trash_1" class="sortable-trash">
<div class="snippet-admin">
<button id="ob_ordnance-add_1" class="sortable-add"></button>
<img id="ob_ordnance-trash_1" class="sortable-trash">
</div>
<span class="spacer"></span>
<span class="small">
<label for="OB_ORDNANCE_WIDTH_1">Width:</label>
<input type="text" class="param" name="OB_ORDNANCE_WIDTH_1" size="5">
<button class="generate" data-id="ob_ordnance_1">Snippet</button>
<div class="snippets-ob">
<label for="ob" class="header">OB:</label>
<label for="OB_ORDNANCE_WIDTH_1">Width:</label>
<input type="text" class="param" name="OB_ORDNANCE_WIDTH_1" size="5">
<button class="generate" data-id="ob_ordnance_1">Snippet</button>
</div>
<div class="snippets-notes">
<label class="header">Notes:</label>
<label for="OB_ORDNANCE_MA_NOTES_WIDTH_1">Width:</label>
<input type="text" class="param" name="OB_ORDNANCE_MA_NOTES_WIDTH_1" size="5">
<button class="generate" data-id="ob_ordnance_ma_notes_1">Snippet</button>
</div>
</span>
</div>
</div>

@ -0,0 +1,182 @@
<!doctype html> <!-- NOTE: For testing porpoises only! -->
<html lang="en">
<script>
var nat = "{{NATIONALITY}}" ;
var vo_type = "{{VO_TYPE}}" ;
var gVehicleOrdnanceNotes = {} ;
</script>
<head>
<meta charset="utf-8">
<style>
.notes .key { font-weight: bold ; }
.ma-note { margin: 0.5em 0 ; padding: 0.25em 0.5em ; border: 1px dotted #444 ; }
.ma-note .key { font-weight: bold ; }
table { margin-top: 2em ; border-collapse: collapse ; }
th { text-align: left ; padding: 0.2em 0.5em ; background: #eee ; border: 1px solid #ccc ; }
td { padding: 0.2em 0.5em ; }
</style>
</head>
<body>
<div id="results" style="display:none;"></div>
</body>
<script src="{{url_for('static',filename='jquery/jquery-3.3.1.min.js')}}"></script>
<script src="{{url_for('static',filename='snippets.js')}}"></script>
<script>
$(document).ready( function () {
// initialize
var vo_notes, vo_entries ;
var on_load_counter = 2 ;
function on_data_loaded() {
if ( --on_load_counter == 0 ) {
// everything's loaded - generate the report
load_vo_notes( vo_notes, vo_entries ) ;
}
}
// get the vehicle/ordnance listings
var url ;
if ( vo_type === "vehicles" )
url = "{{url_for( 'get_vehicle_listings', report=1 )}}" ; // nb: includes landing craft
else
url = "{{url_for( 'get_ordnance_listings', report=1 )}}" ;
$.getJSON( url, function( data ) {
vo_entries = data[ nat.substring(nat.length-6) === "-minor" ? nat+"-common" : nat ] ;
on_data_loaded() ;
} ).fail( function( xhr, status, errorMsg ) {
alert( "Can't get the {{VO_TYPE0}} listings:\n\n" + errorMsg ) ;
} ) ;
// get the vehicle/ordnance notes
if ( vo_type === "vehicles" )
url = "{{url_for('get_vehicle_notes')}}" ; // nb: includes landing craft
else
url = "{{url_for('get_ordnance_notes')}}" ;
$.getJSON( url, function( data ) {
gVehicleOrdnanceNotes[vo_type] = data ;
vo_notes = data[ nat ] ;
on_data_loaded() ;
} ).fail( function( xhr, status, errorMsg ) {
alert( "Can't get the vehicle/ordnance notes:\n\n" + errorMsg ) ;
} ) ;
} ) ;
function load_vo_notes( vo_notes, vo_entries )
{
// initialize
var vo_type2 = (vo_type === "vehicles" ? "vehicle" : vo_type ) ;
var header = nat[0].toUpperCase() + nat.substring(1) + " " + vo_type2[0].toUpperCase() + vo_type2.substring(1) + " Notes" ;
document.title = header ;
var buf = [] ;
buf.push( "<h2>", header, "</h2>" ) ;
// show the vehicle/ordnance notes
if ( ! vo_notes )
buf.push( "<p> None found." ) ;
else {
var keys = Object.keys( vo_notes ) ;
function parse_key( val ) {
var pos = val.indexOf( "." ) ;
if ( pos === -1 )
return [ parseInt(val), 0 ] ;
else
return [ parseInt(val.substring(0,pos)), parseInt(val.substring(pos+1)) ] ;
}
keys.sort( function( lhs, rhs ) {
if ( lhs === "multi-applicable" && rhs === "multi-applicable" )
return 0 ;
else if ( lhs === "multi-applicable" )
return +1 ;
else if ( rhs === "multi-applicable" )
return -1 ;
var lhs = parse_key( lhs ) ;
var rhs = parse_key( rhs ) ;
if ( lhs[0] < rhs[0] )
return -1 ;
else if ( lhs[0] > rhs[0] )
return +1 ;
if ( lhs[1] < rhs[1] )
return -1 ;
else if ( lhs[1] > rhs[1] )
return +1 ;
return 0 ;
} ) ;
buf.push( "<table id='vo-notes'>" ) ;
for ( var i=0 ; i < keys.length ; ++i ) {
if ( keys[i] === "multi-applicable" )
continue ;
buf.push( "<tr>", "<td class='key'>", keys[i]+":", "<td>", vo_notes[keys[i]] ) ;
}
buf.push( "</table>" ) ;
}
// show each multi-applicable note
buf.push( "<h4> Multi-Applicable Notes </h4>" ) ;
ma_notes = vo_notes ? vo_notes["multi-applicable"] : null ;
if ( ! ma_notes )
buf.push( "<p> None found." ) ;
else {
var keys = sort_ma_notes_keys( nat, Object.keys(ma_notes) ) ;
if ( keys ) {
for ( var i=0 ; i < keys.length ; ++i ) {
buf.push( "<div class='ma-note'>" ) ;
buf.push( "<div class='key'>", keys[i]+": ", "</div>" ) ;
buf.push( "<div class='content'>", ma_notes[keys[i]], "</div>" ) ;
buf.push( "</div>" ) ;
}
}
}
// show the multi-applicable notes for each vehicle/ordnance
buf.push( "<table id='vo-entries'>" ) ;
buf.push( "<tr>", "<th> Name", "<th> Raw note#", "<th> Extracted note#", "<th> Raw m/a keys", "<th> Extracted m/a keys", "<th> Unrecognized", "<th> Missing" ) ;
for ( var i=0 ; i < vo_entries.length ; ++i ) {
var vo_entry = vo_entries[i] ;
buf.push( "<tr>" ) ;
buf.push( "<td class='name'>", vo_entry.name ) ;
buf.push( "<td class='vo-note-raw'>", vo_entry.note_number) ;
var vo_note_key = get_vo_note_key( vo_entry ) ;
if ( vo_note_key ) {
if ( ! is_known_vo_note_key( vo_type, nat, vo_note_key ) )
vo_note_key += " (missing)" ;
}
buf.push( "<td class='vo-note'>", vo_note_key ) ;
buf.push( "<td class='ma-notes-raw'>", vo_entry.notes ) ;
var result = get_ma_notes_keys( nat, [vo_entry], vo_type ) ;
var keys = result[0] ;
if ( result[1] || result[2] || result[3] )
buf.push( "*** UNEXPECTED EXTRA NOTES ***" ) ;
buf.push( "<td class='ma-notes'>", keys ) ;
var unrecognized = [] ;
for ( var j=0 ; j < result[4].length ; ++j )
unrecognized.push( result[4][j][1] ) ;
buf.push( "<td class='unrecognized'>", unrecognized ) ;
buf.push( "<td class='missing'>", find_missing_ma_notes(ma_notes,keys) ) ;
}
buf.push( "</table>" ) ;
var $results = $("#results") ;
$results.html( buf.join("") ).show() ;
}
function find_missing_ma_notes( ma_notes, keys )
{
// find Multi-Applicable Notes that are referenced but not defined
if ( ! keys )
return null ;
var missing_keys = [] ;
for ( var i=0 ; i < keys.length ; ++i ) {
if ( !ma_notes || !( keys[i] in ma_notes ) )
missing_keys.push( keys[i] ) ;
}
return missing_keys ;
}
</script>
</html>

@ -22,7 +22,7 @@ td { padding: 0.2em 0.5em ; }
<script>
$(document).ready( function () {
// get the vehicle listings
// get the vehicle/ordnance listings
var url ;
if ( "{{VO_TYPE}}" == "ordnance" )
url = "{{url_for( 'get_ordnance_listings', report=1 )}}" ;

@ -27,7 +27,7 @@ def control_tests( action ):
sig = inspect.signature( func )
kwargs = {}
for param in sig.parameters.values():
if param.name in ("vengine","vmod","gpids","ddtype","fname","dname"):
if param.name in ("vengine","vmod","gpids","dtype","fname","dname"):
kwargs[ param.name ] = request.args.get( param.name, param.default )
# execute the command

@ -38,6 +38,18 @@
"japanese": {
"display_name": "Japanese",
"ob_colors": [ "OBCOL:japanese","OBCOL2:japanese", "OBCOL-BORDER:japanese" ]
},
"dutch": {
"display_name": "Dutch",
"ob_colors": [ "OBCOL:dutch","OBCOL2:dutch", "OBCOL-BORDER:dutch" ],
"type": "allied-minor"
},
"romanian": {
"display_name": "Romanian",
"ob_colors": [ "OBCOL:romanian","OBCOL2:romanian", "OBCOL-BORDER:romanian" ],
"type": "axis-minor"
}
}

@ -0,0 +1,8 @@
{%for ma_note in OB_ORDNANCE_MA_NOTES%} [*] {{ma_note}}
{%endfor%}
{%if OB_ORDNANCE_EXTRA_MA_NOTES%}
{%if OB_ORDNANCE_EXTRA_MA_NOTES_CAPTION%} === {{OB_ORDNANCE_EXTRA_MA_NOTES_CAPTION}} === {%endif%}
{%for ma_note in OB_ORDNANCE_EXTRA_MA_NOTES%} [*] {{ma_note}}
{%endfor%}
{%endif%}

@ -0,0 +1,8 @@
{%for ma_note in OB_VEHICLES_MA_NOTES%} [*] {{ma_note}}
{%endfor%}
{%if OB_VEHICLES_EXTRA_MA_NOTES%}
{%if OB_VEHICLES_EXTRA_MA_NOTES_CAPTION%} === {{OB_VEHICLES_EXTRA_MA_NOTES_CAPTION}} === {%endif%}
{%for ma_note in OB_VEHICLES_EXTRA_MA_NOTES%} [*] {{ma_note}}
{%endfor%}
{%endif%}

@ -0,0 +1,9 @@
[
{ "name": "common allied minor ordnance",
"note_number": "102\u2020",
"notes": [ "A", "Du" ],
"id": "alc/o:000"
}
]

@ -0,0 +1,9 @@
[
{ "name": "dutch ordnance",
"note_number": "2\u2020",
"notes": [ "A", "Du" ],
"id": "du/o:000"
}
]

@ -0,0 +1,9 @@
[
{ "name": "common axis minor ordnance",
"note_number": "104\u2020",
"notes": [ "A", "Ro" ],
"id": "axc/o:000"
}
]

@ -0,0 +1,9 @@
[
{ "name": "romanian ordnance",
"note_number": "4\u2020",
"notes": [ "A", "Ro" ],
"id": "ro/o:000"
}
]

@ -0,0 +1,12 @@
[
{ "name": "Cannone-aa da 90/53",
"type": "AA",
"capabilities": [ "T" ],
"note_number": "20\u2020",
"notes": [ "N", "<s>R</s>" ],
"id": "it/o:019",
"gpid": 3464
}
]

@ -11,6 +11,7 @@
{ "name": "another russian ordnance",
"capabilities": [ "RFNM" ],
"note_number": "2",
"notes": [ "ZZ" ],
"id": "ru/o:991"
},
{ "name": "name only",

@ -0,0 +1,9 @@
[
{ "name": "common allied minor vehicle",
"note_number": "101\u2020",
"notes": [ "A", "Du" ],
"id": "alc/v:000"
}
]

@ -0,0 +1,10 @@
[
{ "name": "dutch vehicle",
"note_number": "1\u2020",
"notes": [ "A", "Du" ],
"id": "du/v:000"
}
]

@ -0,0 +1,9 @@
[
{ "name": "common axis minor vehicle",
"note_number": "103\u2020",
"notes": [ "A", "Ro" ],
"id": "axc/v:000"
}
]

@ -0,0 +1,10 @@
[
{ "name": "romanian vehicle",
"note_number": "3\u2020",
"notes": [ "A", "Ro" ],
"id": "ro/v:000"
}
]

@ -13,10 +13,17 @@
"capabilities": [ "QSU" ],
"cs#": "4:brewup",
"note_number": "2",
"notes": [ "<s>b</s>", "C" ],
"id": "ge/v:991"
},
{ "name": "name only",
{ "name": "one more german vehicle",
"capabilities": [],
"note_number": "3",
"notes": [ "A", "C" ],
"id": "ge/v:992"
},
{ "name": "name only",
"id": "ge/v:999"
}
]

@ -0,0 +1,12 @@
[
{ "name": "SMV L40 47/32",
"type": "TD",
"CS#": 3,
"note_number": "15\u2020",
"notes": [ "N<sup>T</sup>", "R" ],
"id": "it/v:017",
"gpid": 3513
}
]

@ -0,0 +1,8 @@
[
{ "name": "japanese vehicle",
"notes": [ "A\u2020<sup>1</sup>" ],
"id": "ja/v:000"
}
]

@ -0,0 +1,14 @@
[
{ "name": "landing craft",
"notes": [ "A" ],
"id": "sh/v:000",
"gpid": [ 399, 397 ]
},
{ "name": "Daihatsu",
"notes": [ "B" ],
"id": "sh/v:007",
"gpid": 417
}
]

@ -13,6 +13,7 @@
"capabilities": [ "RFNM" ],
"cs#": 4,
"note_number": "2",
"notes": [ "N", "<s>B</s>" ],
"id": "ru/v:991"
},
{ "name": "name only",

@ -0,0 +1 @@
{"SCENARIO_NAME":"Modified scenario name (<>{}\"'\\)","SCENARIO_ID":"xyz123","SCENARIO_LOCATION":"Right here","SCENARIO_DATE":"1945-12-31","SCENARIO_WIDTH":"101","VICTORY_CONDITIONS_WIDTH":"102","SSR_WIDTH":"103","OB_VEHICLES_WIDTH_1":"202","OB_VEHICLES_MA_NOTES_WIDTH_1":"203","OB_ORDNANCE_WIDTH_1":"204","OB_ORDNANCE_MA_NOTES_WIDTH_1":"205","OB_VEHICLES_WIDTH_2":"302","OB_VEHICLES_MA_NOTES_WIDTH_2":"303","OB_ORDNANCE_WIDTH_2":"304","OB_ORDNANCE_MA_NOTES_WIDTH_2":"305","VICTORY_CONDITIONS":"Just do it!","SCENARIO_THEATER":"PTO","PLAYER_1":"russian","PLAYER_1_ELR":"5","PLAYER_1_SAN":"4","PLAYER_2":"german","PLAYER_2_ELR":"3","PLAYER_2_SAN":"2","SSR":["Modified SSR #1","Modified SSR #2"],"OB_VEHICLES_1":[{"id":"ru/v:027","name":"T-34/85"}],"OB_VEHICLES_2":[{"id":"ge/v:030","name":"PzKpfw VG"}],"OB_ORDNANCE_1":[{"id":"ru/o:002","name":"82mm BM obr. 37"}],"OB_ORDNANCE_2":[{"id":"ge/o:005","name":"3.7cm PaK 35/36"}],"SCENARIO_NOTES":[{"caption":"Modified scenario note #1","width":"","id":1},{"caption":"Modified scenario note #2","width":"100px","id":2}],"OB_SETUPS_1":[{"caption":"Modified Russian setup #1","width":"","id":1},{"caption":"Modified Russian setup #2","width":"200px","id":2},{"caption":"Modified Russian setup #3","width":"","id":3},{"caption":"Modified Russian setup #4","width":"","id":4},{"caption":"Modified Russian setup #5","width":"","id":5}],"OB_SETUPS_2":[{"caption":"Modified German setup #1","width":"","id":1}],"OB_NOTES_1":[{"caption":"Modified Russian note #1","width":"10em","id":1}],"OB_NOTES_2":[{"caption":"Modified German note #1","width":"","id":1},{"caption":"Modified German note #2","width":"","id":2},{"caption":"Modified German note #3","width":"","id":3},{"caption":"Modified German note #4","width":"","id":4},{"caption":"Modified German note #5","width":"","id":5}],"_app_version":"v0.7","_last_update_time":"2018-12-16T03:30:01.845Z","_creation_time":"2018-12-16T03:30:01.845Z"}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

@ -0,0 +1 @@
Allied Minor Multi-Applicable Ordnance Note "A".

@ -0,0 +1 @@
Allied Minor Multi-Applicable Ordnance Note "Du".

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

@ -0,0 +1 @@
Allied Minor Multi-Applicable Vehicle Note "A".

@ -0,0 +1 @@
Allied Minor Multi-Applicable Vehicle Note "Du".

@ -0,0 +1 @@
American Multi-Applicable Vehicle Note "A".

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

@ -0,0 +1 @@
Axis Minor Multi-Applicable Ordnance Note "A".

@ -0,0 +1 @@
Axis Minor Multi-Applicable Ordnance Note "Ro".

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

@ -0,0 +1 @@
Axis Minor Multi-Applicable Vehicle Note "A".

@ -0,0 +1 @@
Axis Minor Multi-Applicable Vehicle Note "Ro".

@ -0,0 +1 @@
British Multi-Applicable Vehicle Note "A".

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

@ -0,0 +1 @@
Dutch Multi-Applicable Ordnance Note "A".

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

@ -0,0 +1 @@
Dutch Multi-Applicable Vehicle Note "A".

@ -0,0 +1 @@
French Multi-Applicable Ordnance Note "A".

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

@ -0,0 +1 @@
German Multi-Applicable Ordnance Note "A".

@ -0,0 +1 @@
German Multi-Applicable Ordnance Note "B".

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

@ -0,0 +1 @@
German Multi-Applicable Vehicle Note "A".

@ -0,0 +1 @@
German Multi-Applicable Vehicle Note "B".

@ -0,0 +1 @@
German Multi-Applicable Vehicle Note "b" (nb: lower-case).

@ -0,0 +1 @@
German Multi-Applicable Vehicle Note "C".

@ -0,0 +1 @@
Italian Multi-Applicable Ordnance Note "R".

@ -0,0 +1 @@
Italian Multi-Applicable Vehicle Note "R".

@ -0,0 +1 @@
Japanese Multi-Applicable Vehicle Note "A".

@ -0,0 +1 @@
Landing Craft Multi-Applicable Note "A".

@ -0,0 +1 @@
Landing Craft Multi-Applicable Note "B".

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

@ -0,0 +1 @@
Romanian Multi-Applicable Ordnance Note "A".

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

@ -0,0 +1 @@
Romanian Multi-Applicable Vehicle Note "A".

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

@ -0,0 +1 @@
Russian Multi-Applicable Vehicle Note "X".

@ -0,0 +1 @@
Russian Multi-Applicable Vehicle Note "Y".

@ -0,0 +1 @@
Russian Multi-Applicable Vehicle Note "ZZ".

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save