From cab39f376915f7109840311c36f6414f35384be2 Mon Sep 17 00:00:00 2001 From: Taka Date: Mon, 9 Jul 2018 07:05:37 +0000 Subject: [PATCH] Added SSR's. --- .../webapp/data/default-templates/ssr.j2 | 2 + vasl_templates/webapp/static/css/main.css | 21 +++++ vasl_templates/webapp/static/generate.js | 6 ++ vasl_templates/webapp/static/images/trash.png | Bin 0 -> 2830 bytes vasl_templates/webapp/static/main.js | 14 +++ vasl_templates/webapp/static/ssr.js | 87 ++++++++++++++++++ vasl_templates/webapp/static/utils.js | 37 +++++++- vasl_templates/webapp/templates/main.html | 9 +- vasl_templates/webapp/tests/test_ssr.py | 70 ++++++++++++++ 9 files changed, 242 insertions(+), 4 deletions(-) create mode 100644 vasl_templates/webapp/data/default-templates/ssr.j2 create mode 100755 vasl_templates/webapp/static/images/trash.png create mode 100644 vasl_templates/webapp/static/ssr.js create mode 100644 vasl_templates/webapp/tests/test_ssr.py diff --git a/vasl_templates/webapp/data/default-templates/ssr.j2 b/vasl_templates/webapp/data/default-templates/ssr.j2 new file mode 100644 index 0000000..70397de --- /dev/null +++ b/vasl_templates/webapp/data/default-templates/ssr.j2 @@ -0,0 +1,2 @@ +{% for ssr in SSR %}(*) [{{ssr}}] +{% endfor %} diff --git a/vasl_templates/webapp/static/css/main.css b/vasl_templates/webapp/static/css/main.css index d7c890f..4f3e7cb 100644 --- a/vasl_templates/webapp/static/css/main.css +++ b/vasl_templates/webapp/static/css/main.css @@ -108,6 +108,21 @@ input[type="text"] { margin-bottom: 0.25em ; } #panel-vc textarea[name="victory_conditions"] { width: calc(100% - 2px) ; height: calc(100% - 1.5em) ; resize: none ; } #panel-vc input[type="button"] { float: right ; } +#panel-ssr #ssr-sortable { width:100% ; height: calc(100% - 1.5em) ; font-size: 80% ; } +#panel-ssr #ssr-sortable { list-style-type: none ; margin: 0 ; padding: 0 ; } +#panel-ssr #ssr-sortable li { + margin-bottom: 2px ; padding: 5px ; + border: 1px dotted #333 ; background: #eee ; +} +#panel-ssr #ssr-sortable li.highlighted { background: #48c8ff ; } +#panel-ssr #ssr-sortable li:hover { cursor: pointer ; } +#panel-ssr input#add-ssr { float: left ; } +#panel-ssr #ssr-trash { margin-left: 5px ; float: left ; height: 1.5em ; } +#panel-ssr input[data-id="ssr"] { float: right ; } + +#ssr-hint { width:100% ; height: calc(100% - 1.5em) ; font-size: 80% ; font-style: italic ; } +#ssr-hint p { margin-bottom: 1em ; } + #panel-obsetup1 textarea[name="ob_setup_1"] { width: calc(100% - 2px) ; height: calc(100% - 1.5em) ; resize: none ; } #panel-obsetup1 input[type="button"] { float: right ; } @@ -116,5 +131,11 @@ input[type="text"] { margin-bottom: 0.25em ; } /* -------------------------------------------------------------------- */ +.ui-dialog.edit-ssr .ui-dialog-titlebar { display: none ; } +.ui-dialog.edit-ssr .ui-dialog-buttonpane { border: none ; padding: 0 ; font-size: 75% ; } +#edit-ssr { padding: 2px ; } +.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 ; } + .growl-title { display: none ; } .growl ul { margin-left: 1em ; } diff --git a/vasl_templates/webapp/static/generate.js b/vasl_templates/webapp/static/generate.js index 41956a3..4c75d15 100644 --- a/vasl_templates/webapp/static/generate.js +++ b/vasl_templates/webapp/static/generate.js @@ -29,6 +29,12 @@ function generate_snippet( $btn ) params.OB_SETUP_COLOR = gNationalities[params.PLAYER_2].ob_colors[0] ; params.OB_SETUP_COLOR_2 = gNationalities[params.PLAYER_2].ob_colors[1] ; } + else if ( template_id === "ssr" ) { + params.SSR = [] ; + $("#ssr-sortable li").each( function() { + params.SSR.push( $(this).text() ) ; + } ) ; + } // check for mandatory parameters if ( template_id in _MANDATORY_PARAMS ) { diff --git a/vasl_templates/webapp/static/images/trash.png b/vasl_templates/webapp/static/images/trash.png new file mode 100755 index 0000000000000000000000000000000000000000..e77a2d61ca30dd69a1b02444add6d9f632e37014 GIT binary patch literal 2830 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 literal 0 HcmV?d00001 diff --git a/vasl_templates/webapp/static/main.js b/vasl_templates/webapp/static/main.js index 0f7dd57..90f7769 100644 --- a/vasl_templates/webapp/static/main.js +++ b/vasl_templates/webapp/static/main.js @@ -12,6 +12,20 @@ $(document).ready( function () { var navHeight = $("#tabs .ui-tabs-nav").height() ; $("input[name='scenario_name']").focus().focus() ; + // initialize + $("#ssr-sortable").sortable( { connectWith: "#ssr-trash", cursor: "move" } ) ; + init_ssr( $("#ssr-sortable li") ) ; + $("#add-ssr").click( add_ssr ) ; + $("#ssr-trash").sortable( { + receive: function( evt, ui ) { ui.item.remove() ; update_ssr_hint() ; } + } ) ; + $("#edit-ssr textarea").keydown( function(evt) { + if ( evt.keyCode == 13 && evt.ctrlKey ) { + $(".ui-dialog.edit-ssr button:contains('OK')").click() ; + evt.preventDefault() ; + } + } ) ; + // load the ELR's and SAN's var buf = [] ; for ( var i=0 ; i <= 5 ; ++i ) // nb: A19.1: ELR is 0-5 diff --git a/vasl_templates/webapp/static/ssr.js b/vasl_templates/webapp/static/ssr.js new file mode 100644 index 0000000..2a6a3fd --- /dev/null +++ b/vasl_templates/webapp/static/ssr.js @@ -0,0 +1,87 @@ + +// -------------------------------------------------------------------- + +function add_ssr() +{ + // add a new SSR + edit_ssr( null ) ; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +function edit_ssr( $elem ) +{ + // let the user edit a SSR's content + $("#edit-ssr textarea").val( $elem ? $elem.text() : "" ) ; + $("#edit-ssr").dialog( { + dialogClass: "edit-ssr", + modal: true, + minWidth: 400, + minHeight: 150, + open: function() { + $(this).height( $(this).height() ) ; // fudge: force the textarea to resize + }, + buttons: { + OK: function() { + var val = $("#edit-ssr textarea").val().trim() ; + if ( $elem ) { + // update the existing SSR + if ( val !== "" ) + $elem.text( val ) ; + else + delete_ssr( $elem ) ; + } + else { + // create a new SSR + if ( val !== "" ) { + var $new_ssr = $( "
  • " ) ; + $new_ssr.text( val ) ; + $("#ssr-sortable").append( $new_ssr ) ; + init_ssr( $new_ssr ) ; + } + } + update_ssr_hint() ; + $(this).dialog( "close" ) ; + }, + Cancel: function() { $(this).dialog( "close" ) ; }, + }, + } ) ; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +function delete_ssr( $elem ) +{ + // delete the SSR + $elem.addClass( "highlighted" ) ; + ask( "Delete this SSR?", escapeHTML($elem.text()), { + "ok": function() { $elem.remove() ; update_ssr_hint() ; }, + "close": function() { $elem.removeClass("highlighted") ; }, + } ) ; +} + +// -------------------------------------------------------------------- + +function init_ssr( $elem ) +{ + // initialize SSR element(s) + $elem.dblclick( function() { + edit_ssr( $(this) ) ; + } ) ; + $elem.click( function( evt ) { + if ( evt.ctrlKey ) + delete_ssr( $(this) ) ; + } ) ; +} + +function update_ssr_hint() +{ + // show/hide the SSR hint + if ( $("#ssr-sortable li").length === 0 ) { + $("#ssr-sortable").hide() ; + $("#ssr-hint").show() ; + } else { + $("#ssr-sortable").show() ; + $("#ssr-hint").hide() ; + } +} diff --git a/vasl_templates/webapp/static/utils.js b/vasl_templates/webapp/static/utils.js index 7a9baeb..af66d93 100644 --- a/vasl_templates/webapp/static/utils.js +++ b/vasl_templates/webapp/static/utils.js @@ -33,6 +33,37 @@ function copyToClipboard( val ) // -------------------------------------------------------------------- +function ask( title, msg, args ) +{ + // ask a question + var $dlg = $("#ask") ; + $dlg.html( msg ) ; + $dlg.dialog( { + modal: true, + title: title, + buttons: { + OK: function() { + $(this).dialog( "close" ) ; + if ( "ok" in args ) + args.ok() ; + }, + Cancel: function() { + $(this).dialog( "close" ) ; + if ( "cancel" in args ) + args.cancel() ; + }, + }, + close: function() { + if ( "close" in args ) + args.close() ; + }, + } ) ; + + return false ; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + function showInfoMsg( msg ) { // show the informational message @@ -40,7 +71,7 @@ function showInfoMsg( msg ) style: "notice", title: null, message: msg, - location: "br", + location: "tr", } ) ; storeMsgForTestSuite( "_last-info_", msg ) ; } @@ -54,7 +85,7 @@ function showWarningMsg( msg ) style: "warning", title: null, message: msg, - location: "br", + location: "tr", } ) ; storeMsgForTestSuite( "_last-warning_", msg ) ; } @@ -68,7 +99,7 @@ function showErrorMsg( msg ) style: "error", title: null, message: msg, - location: "br", + location: "tr", fixed: true, } ) ; storeMsgForTestSuite( "_last-error_", msg ) ; diff --git a/vasl_templates/webapp/templates/main.html b/vasl_templates/webapp/templates/main.html index c99cb80..2d16dfd 100644 --- a/vasl_templates/webapp/templates/main.html +++ b/vasl_templates/webapp/templates/main.html @@ -45,7 +45,10 @@
    -
    SSR +
    SSR's +

    Click on the "+" below to add a new SSR, double-click on an SSR to edit it.

    To re-order the SSR's, use the mouse to drag them around.

    Ctrl-click on an SSR to delete it, or drag it into the trashcan below.

    + +
    @@ -91,6 +94,9 @@ + + + @@ -104,6 +110,7 @@ gGetNationalitiesUrl = "{{url_for('get_nationalities')}}" ; + diff --git a/vasl_templates/webapp/tests/test_ssr.py b/vasl_templates/webapp/tests/test_ssr.py new file mode 100644 index 0000000..a9bd3b8 --- /dev/null +++ b/vasl_templates/webapp/tests/test_ssr.py @@ -0,0 +1,70 @@ +""" Test generating SSR snippets. """ + +import html + +from selenium.webdriver.common.action_chains import ActionChains + +from vasl_templates.webapp.tests.utils import get_clipboard, find_child, find_children + +# --------------------------------------------------------------------- + +def test_ssr( webapp, webdriver ): + """Test generating SSR snippets.""" + + # initialize + webdriver.get( webapp.url_for( "main" ) ) + + # initialize + expected = [] + def add_ssr( val ): + """Add a new SSR, and check that the SSR snippet is generated correctly.""" + # add the SSR + expected.append( val ) + elem = find_child( webdriver, "#add-ssr" ) + elem.click() + edit_ssr( val ) + def edit_ssr( val ): + """Edit an SSR's content, and check that the SSR snippet is generated correctly.""" + # edit the SSR content + textarea = find_child( webdriver, "#edit-ssr textarea" ) + textarea.clear() + textarea.send_keys( val ) + btn = next( + elem for elem in find_children(webdriver,".ui-dialog.edit-ssr button") + if elem.text == "OK" + ) + btn.click() + # check the generated snippet + check_snippet() + def check_snippet(): + """Check the generated SSR snippet.""" + btn = find_child( webdriver, "input[type='button'][data-id='ssr']" ) + btn.click() + val = "\n".join( "(*) [{}]".format(e) for e in expected ) + assert html.unescape(get_clipboard().strip()) == val + + # add an SSR and generate the SSR snippet + add_ssr( "This is my first SSR." ) + + # add an SSR that contains HTML + add_ssr( "This snippet contains bold and italic text." ) + + # add a multi-line SSR + add_ssr( "line 1\nline 2\nline 3" ) + + # edit one of the SSR's + elems = find_children( webdriver, "#ssr-sortable li" ) + assert len(elems) == 3 + elem = elems[1] + ActionChains(webdriver).double_click( elem ).perform() + expected[1] = "This SSR was modified." + edit_ssr( expected[1] ) + + # delete one of the SSR's + elems = find_children( webdriver, "#ssr-sortable li" ) + assert len(elems) == 3 + elem = elems[1] + trash = find_child( webdriver, "#ssr-trash" ) + ActionChains(webdriver).drag_and_drop( elem, trash ).perform() + del expected[1] + check_snippet()