Create attractive VASL scenarios, with loads of useful information embedded to assist with game play. https://vasl-templates.org
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
vasl-templates/vasl_templates/webapp/static/sortable.js

267 lines
10 KiB

SORTABLE_DISPLAY_NAMES = {
scenario_notes: [ "scenario note", "scenario notes", "a" ],
ssr: [ "SSR", "SSR's", "a" ],
ob_setups: [ "OB setup note", "OB setup notes", "an" ],
ob_notes: [ "OB setup note", "OB setup notes", "an" ],
ob_vehicles: [ "vehicle", "vehicles", "a" ],
ob_ordnance: [ "ordnance", "ordnance", "an" ],
vo_capabilities: [ "capability", "capabilities", "a" ],
vo_comments: [ "comment", "comments", "a" ],
} ;
SORTABLE_HINTS = {
scenario_notes: "Add miscellaneous scenario notes here.",
ssr: "Add scenario SSR's here.",
ob_setups: "Add setup notes for the player's OB here.",
ob_notes: "Add miscellaneous setup notes here.",
ob_vehicles: "Add vehicles in the player's OB here.",
ob_ordnance: "Add ordnance in the player's OB here.",
} ;
// --------------------------------------------------------------------
( function( $ ) {
$.fn.sortable2 = function( action, args )
{
var actions = {
"init": init_sortable2,
"add": function( $sortable2 ) {
// add a new entry to the sortable2
var $entry = $( "<li></li>" ) ;
$entry.append( args.content ) ;
$entry.data( "sortable2-data", args.data ) ;
init_entry( $sortable2, $entry ) ;
$sortable2.append( $entry ) ;
adjust_entry_heights( $sortable2 ) ;
// update the hint
update_hint( $sortable2 ) ;
return $entry ;
},
"delete": function( $sortable2 ) {
// delete the entry from the sortable2
delete_entry( $sortable2, args.entry ) ;
},
"delete-all": function( $sortable2 ) {
// delete all entries from the sortable2
$sortable2.children( "li" ).each( function() {
$(this).remove() ;
} ) ;
update_hint( $sortable2 ) ;
},
"adjust-entry-heights": function( $sortable2 ) {
adjust_entry_heights( $sortable2 ) ;
},
"get-entry-data": function( $sortable2 ) {
// get the data associated with each sortable2 entry
var entry_data = [] ;
$sortable2.children( "li" ).each( function() {
entry_data.push( $(this).data( "sortable2-data" ) ) ;
} ) ;
return entry_data ;
},
} ;
function init_sortable2( $sortable2 )
{
// get the display name
var display_name = SORTABLE_DISPLAY_NAMES[ get_sortable2_type($sortable2) ] ;
// initialize the sortable2 and support elements
$sortable2.data( "no_confirm_delete", args.no_confirm_delete ) ;
$sortable2.data( "on_edit", args.edit ) ;
var $add_btn = find_helper( $sortable2, "add" ) ;
$add_btn.prepend( $( "<div style='display:flex;align-items:center;whitespace:nowrap;'>" +
"<img src='" + gImagesBaseUrl + "/sortable-add.png' class='sortable-add'>" +
"Add" +
"</div>"
) ).button( {} ) ;
var $add = find_helper( $sortable2, "add" ) ;
$add.prop( "title", "Add a new " + display_name[0] )
.click( args.add ) ;
if ( args.reset ) {
$sortable2.data( "on_reset", args.reset ) ;
var $reset_btn = find_helper( $sortable2, "reset" ) ;
$reset_btn.prepend( $( "<div style=display:flex;align-items:center;'whitespace:nowrap;'><img src='" + gImagesBaseUrl + "/sortable-reset.png' class='sortable-reset'> Reset</div>" ) )
.button( {} ) ;
var $reset = find_helper( $sortable2, "reset" ) ;
$reset.prop( "title", "Reset the " + display_name[1] )
.click( args.reset ) ;
}
// handle overflow when there are too many entries
// NOTE: We do this by setting the height of the entry list fairly low; if there are
// a lot of entries, they will render outside its box, but this triggers the v-scrollbar
// on the parent .content box. There seems to be an odd interaction with the main flexbox
// if there are 2 overflowing entry lists and the main browser v-scrollbar appears,
// but we can live with that, for now...
$sortable2.css( "height", "5em" ) ; // nb: also effectively acts as a min-height
$sortable2.parent().css( "overflow-y", "auto" ) ;
// handle dragging entries to the trash
var $trash = find_helper( $sortable2, "trash" ) ;
$trash.prop( "src", gImagesBaseUrl + "/trash.png" )
.prop( "title", "Drag " + display_name[2] + " " + display_name[0] + " here to delete it." ) ;
$sortable2.sortable( {
stop: function( evt, ui ) { set_entry_colors( ui.item, false ) ; },
connectWith: $trash, cursor: "move"
} ) ;
$trash.sortable( {
receive: function( evt, ui ) {
ui.item.remove() ;
adjust_entry_heights( $sortable2 ) ;
update_hint( $sortable2 ) ;
}
} ) ;
}
function init_entry( $sortable2, $entry )
{
// initialize the sortable2 entry
var on_edit = $sortable2.data( "on_edit" ) ;
if ( on_edit ) {
$entry.dblclick( function() { // double-click => edit the entry
on_edit( $sortable2, $entry ) ;
} ) ;
}
$entry.click( function( evt ) {
if ( evt.ctrlKey )
delete_entry( $sortable2, $(this) ) ; // ctrl-click => delete the entry
else if ( evt.shiftKey ) {
var $elem = $(this).find( "img.snippet" ) ;
if ( $elem.length !== 0 )
$elem.click() ; // shift-click => generate snippet
}
} ) ;
// style the entry
// NOTE: Colors aren't going to work when we're using the test template pack!
var colors = get_player_colors_for_element($sortable2) || ["#f0f0f0","#e0e0e0","#c0c0c0"] ;
$entry.data( "colors", colors ) ;
set_entry_colors( $entry, false ) ;
$entry.on( {
"mouseenter": function() { set_entry_colors( $entry, true ) ; },
"mouseleave": function() { set_entry_colors( $entry, false ) ; }
} ) ;
}
function delete_entry( $sortable2, $entry )
{
function do_delete_entry() {
$entry.remove() ;
adjust_entry_heights( $sortable2 ) ;
update_hint( $sortable2 ) ;
}
if ( $sortable2.data( "no_confirm_delete" ) ) {
do_delete_entry() ;
return ;
}
// ask if it's OK to delete the entry
set_entry_colors( $entry, true ) ;
var caption = $entry.data( "sortable2-data" ).caption ;
if ( ! caption )
caption = $entry.html() ;
var display_name = SORTABLE_DISPLAY_NAMES[ get_sortable2_type($sortable2) ] ;
var buf = [
"OK to delete this " + display_name[0] + "?",
"<div style='margin:1em 0 0 1em;font-size:80%;font-style:italic;'>",
caption,
"</div>"
] ;
ask( "Delete " + display_name[0],
buf.join(""), {
width: 350,
ok: do_delete_entry,
close: function() { set_entry_colors( $entry, false ) ; },
} ) ;
}
function update_hint( $sortable2 ) {
// show/hide the hint
var $hint = find_helper( $sortable2, "hint" ) ;
if ( $hint.length === 0 )
return ;
if ( $sortable2.children("li").length === 0 ) {
$sortable2.hide() ;
var display_name = SORTABLE_DISPLAY_NAMES[ get_sortable2_type($sortable2) ] ;
var img = "<img src='" + gImagesBaseUrl + "/sortable-add.png' style='height:12px;margin-bottom:-1px;'>" ;
var buf = [
SORTABLE_HINTS[ get_sortable2_type($sortable2) ],
"<ul class='instructions'>",
"<li>Click on the " + img + " below to add a new " + display_name[0] + ".",
"<li>To re-order the " + display_name[1] + ", use the mouse to drag them around.",
"<li>Ctrl-click on " + display_name[2] + " " + display_name[0] + " to delete it, or drag it into the trashcan below.",
"</ul>",
] ;
$hint.html( buf.join("") ) ;
$hint.show() ;
} else {
$sortable2.show() ;
$hint.hide() ;
}
}
function adjust_entry_heights( $sortable2 ) {
// adjust the max height of each item based on how many items there are
var $entries = $sortable2.children( "li" ) ;
if ( $entries.length === 0 )
return ;
// NOTE: We can't get height for sortable2's that are not visible (i.e. not in the active tab),
// we update the heights dynamically as tabs are selected, and the window is resized.
var available_height = $sortable2.parent().height() ;
var max_height = Math.ceil( Math.max( available_height/$entries.length, 2*gEmSize ) ) ;
$entries.each( function() {
var fixed_height = $(this).data( "sortable2-data" ).fixed_height ;
if ( fixed_height )
$(this).css( "height", fixed_height ) ;
else
$(this).css({ "max-height": max_height+"px", "overflow-y": "hidden" }) ;
// check for overflow
var entry_height = $(this).height() ;
var content_height = $(this).children("div").height() ;
// FIXME! We should show a visual cue that the entry is truncated.
} ) ;
}
function set_entry_colors( $entry, invert )
{
// set the entry colors
var colors = $entry.data( "colors" ) ;
if ( ! colors )
return ;
if ( $entry.hasClass( "ui-sortable-helper" ) )
invert = true ; // nb: drag is in progress
$entry.css( {
"background": colors[invert?1:0],
"border-bottom": "1px solid "+colors[2],
"border-right": "1px solid "+colors[2],
} ) ;
}
function find_helper( $sortable2, type ) {
// find a helper element for the sortable2
var id = $sortable2.prop( "id" ) ;
var pos = id.indexOf( "-sortable" ) ;
return $( "#" + get_sortable2_type($sortable2) + "-" + type + id.substring(pos+9) ) ;
}
function get_sortable2_type( $sortable2 ) {
// get the sortable2 type
var id = $sortable2.prop( "id" ) ;
var pos = id.indexOf( "-sortable" ) ;
return id.substring( 0, pos ) ;
}
// execute the specified action
var retval = actions[action]( this ) ;
return (retval !== undefined) ? retval : this ;
} ;
} ) ( jQuery ) ;