diff --git a/resources/css/style.css b/resources/css/style.css index 54ec151..f6e8cfd 100644 --- a/resources/css/style.css +++ b/resources/css/style.css @@ -39,8 +39,10 @@ svg text{ float: left; border: 1px solid black; height: 30px; + min-width: 30px; background: white; padding: 3px; + text-align: center; } .menu .list{ @@ -62,6 +64,8 @@ svg text{ position: relative; border: 1px solid black; height: 30px; + min-width: 30px; + text-align: center; float: left; } diff --git a/resources/js/plan.js b/resources/js/plan.js index 2a2fed5..0f3806f 100644 --- a/resources/js/plan.js +++ b/resources/js/plan.js @@ -1,6 +1,8 @@ const ADD = 'add'; +const MOVE = 'move'; const SQUARE = 30; const BODY = 'body'; +const DIV = 'DIV'; const SVG = 'svg'; const PLAN = 'plan'; const POST = 'POST'; @@ -27,19 +29,20 @@ function addTile(x,y){ addMessage(resp); } }); - } function bodyClick(ev){ - //console.log('bodyClick:',ev); + console.log('bodyClick:',ev); switch (mode){ case undefined: case null: return clickTile(ev.clientX,ev.clientY); case ADD: return addTile(ev.clientX,ev.clientY); + case MOVE: + return moveTile(ev.clientX,ev.clientY); } - console.log(ev.clientX,ev.clientY); + console.log('unknown action "'+mode+'" @ ('+ev.clientX+','+ev.clientY+')'); } function clickTile(x,y){ @@ -83,11 +86,46 @@ function enableAdding(ev){ return false; // otherwise body.click would also be triggered } +function enableMove(ev){ + console.log('enableMove:',ev); + if (selected != null) $(selected).css('border',''); + selected = ev.target; + while (selected != null && selected.nodeName != DIV) selected = selected.parentNode; + if (selected == null){ + mode = null; + } else { + $(selected).css('border','2px solid red'); + $('.menu .move .list').css('display','inherit'); + mode = MOVE; + } + return false; // otherwise body.click would also be triggered +} + +function moveTile(x,y){ + console.log("moveTile:",selected.id,x,y); + x = Math.floor(x/SQUARE); + y = Math.floor(y/SQUARE); + $.ajax({ + url : PLAN, + method: POST, + data : {action:mode,direction:selected.id,x:x,y:y}, + success: function(resp){ + $(resp).each(function(){ + if (this.id != undefined){ + $('#'+this.id).remove(); + $(BODY).append($(this)); + } + }); + $('#tile-'+x+'-'+y).remove(); + } + }); +} + function savePlan(ev){ $.ajax({ url : PLAN, method : POST, - data : {action:'save',name:'default'}, // todo: ask for name + data : {action:'save',name:'default'}, // TODO: ask for name success: function(resp){ addMessage(resp);} }); return false; @@ -97,6 +135,7 @@ window.onload = function () { var isDragging = false; $('.menu > div').click(closeMenu); $('.menu .addtile .list svg').click(enableAdding); + $('.menu .move .list div').click(enableMove); $(BODY).click(bodyClick); $('#save').click(savePlan); } diff --git a/resources/svg/TurnoutEN.svg b/resources/svg/TurnoutEN.svg new file mode 100644 index 0000000..74eb417 --- /dev/null +++ b/resources/svg/TurnoutEN.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/resources/svg/TurnoutES.svg b/resources/svg/TurnoutES.svg new file mode 100644 index 0000000..347786e --- /dev/null +++ b/resources/svg/TurnoutES.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/resources/svg/TurnoutWN.svg b/resources/svg/TurnoutWN.svg new file mode 100644 index 0000000..8bf393c --- /dev/null +++ b/resources/svg/TurnoutWN.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/src/main/java/de/srsoftware/web4rail/Application.java b/src/main/java/de/srsoftware/web4rail/Application.java index 609ac82..f14248d 100644 --- a/src/main/java/de/srsoftware/web4rail/Application.java +++ b/src/main/java/de/srsoftware/web4rail/Application.java @@ -92,7 +92,7 @@ public class Application { html = ((Page)response).html().toString().getBytes(UTF8); client.getResponseHeaders().add("content-type", "text/html"); } else { - html = response.toString().getBytes(UTF8); + html = (response == null ? "" : response.toString()).getBytes(UTF8); client.getResponseHeaders().add("content-type", "text/plain"); } diff --git a/src/main/java/de/srsoftware/web4rail/Plan.java b/src/main/java/de/srsoftware/web4rail/Plan.java index 3b0b91e..c70736a 100644 --- a/src/main/java/de/srsoftware/web4rail/Plan.java +++ b/src/main/java/de/srsoftware/web4rail/Plan.java @@ -9,6 +9,7 @@ import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.util.HashMap; import java.util.Map.Entry; +import java.util.Vector; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -25,8 +26,11 @@ import de.srsoftware.web4rail.tiles.Eraser; import de.srsoftware.web4rail.tiles.StraightH; import de.srsoftware.web4rail.tiles.StraightV; import de.srsoftware.web4rail.tiles.Tile; +import de.srsoftware.web4rail.tiles.TurnoutEN; +import de.srsoftware.web4rail.tiles.TurnoutES; import de.srsoftware.web4rail.tiles.TurnoutSE; import de.srsoftware.web4rail.tiles.TurnoutSW; +import de.srsoftware.web4rail.tiles.TurnoutWN; import de.srsoftware.web4rail.tiles.TurnoutWS; public class Plan { @@ -39,13 +43,15 @@ public class Plan { private static final String Y = "y"; private static final String NAME = "name"; private static final String ACTION_PROPS = "openProps"; + private static final String ACTION_MOVE = "move"; + private static final String DIRECTION = "direction"; + private static final String EAST = "east"; + private static final String WEST = "west"; private HashMap> tiles = new HashMap>(); private Tag actionMenu() throws IOException { - - Tag tileMenu = new Tag("div").clazz("actions").content(t("Actions")); - + Tag tileMenu = new Tag("div").clazz("actions").content(t("Actions")); StringBuffer tiles = new StringBuffer(); tiles.append(new Tag("div").id("save").content(t("Save plan"))); return new Tag("div").clazz("list").content(tiles.toString()).addTo(tileMenu); @@ -99,13 +105,20 @@ public class Plan { private Tag menu() throws IOException { Tag menu = new Tag("div").clazz("menu"); - - tileMenu().addTo(menu); actionMenu().addTo(menu); - + moveMenu().addTo(menu); + tileMenu().addTo(menu); return menu; } + private Tag moveMenu() { + Tag tileMenu = new Tag("div").clazz("move").title(t("Move tiles")).content(t("↹")); + StringBuffer tiles = new StringBuffer(); + tiles.append(new Tag("div").id("west").title(t("Move west")).content("🢀")); + tiles.append(new Tag("div").id("east").title(t("Move east")).content("🢂")); + return new Tag("div").clazz("list").content(tiles.toString()).addTo(tileMenu); + } + public Object process(HashMap params) { try { String action = params.get(ACTION); @@ -115,10 +128,12 @@ public class Plan { case ACTION_ADD: Tile tile = addTile(params.get(TILE),params.get(X),params.get(Y)); return t("Added {}",tile.getClass().getSimpleName()); - case ACTION_SAVE: - return saveTo(params.get(NAME)); + case ACTION_MOVE: + return moveTile(params.get(DIRECTION),params.get(X),params.get(Y)); case ACTION_PROPS: return Tile.propMenu(); + case ACTION_SAVE: + return saveTo(params.get(NAME)); default: LOG.warn("Unknown action: {}",action); } @@ -128,6 +143,40 @@ public class Plan { } } + private String moveTile(String direction, String x, String y) throws NumberFormatException, IOException { + return moveTile(direction,Integer.parseInt(x),Integer.parseInt(y)); + } + + private String moveTile(String direction, int x, int y) throws IOException { + LOG.debug("moveTile({},{},{})",direction,x,y); + Vector moved = null; + switch (direction) { + case EAST: + moved = moveHorizontal(x,y,+1); + break; + case WEST: + moved = moveHorizontal(x,y,-1); + break; + } + if (!moved.isEmpty()) { + set(x,y,null); + StringBuilder sb = new StringBuilder(); + for (Tile tile : moved) sb.append(tile.html()+"\n"); + return sb.toString(); + } + return null; + } + + private Vector moveHorizontal(int x, int y,int step) { + LOG.debug("moveEast({},{})",x,y); + Tile tile = this.get(x, y); + if (tile == null) return new Vector(); + Vector result = moveHorizontal(x+step,y,step); + set(x+step, y, tile); + result.add(tile); + return result; + } + private String saveTo(String name) throws IOException { if (name == null || name.isEmpty()) throw new NullPointerException("Name must not be empty!"); File file = new File(name+".plan"); @@ -152,7 +201,7 @@ public class Plan { tiles.put(x, column); } old = column.remove(y); - if (!(tile instanceof Eraser)) column.put(y,tile.position(x, y)); + if (tile != null && !(tile instanceof Eraser)) column.put(y,tile.position(x, y)); return old; } @@ -161,7 +210,7 @@ public class Plan { } private Tag tileMenu() throws IOException { - Tag tileMenu = new Tag("div").clazz("addtile").content(t("Add tile")); + Tag tileMenu = new Tag("div").clazz("addtile").title(t("Add tile")).content("◫"); StringBuffer tiles = new StringBuffer(); tiles.append(new StraightH().html()); @@ -173,7 +222,10 @@ public class Plan { tiles.append(new EndE().html()); tiles.append(new EndW().html()); tiles.append(new TurnoutSE().html()); + tiles.append(new TurnoutEN().html()); + tiles.append(new TurnoutES().html()); tiles.append(new TurnoutWS().html()); + tiles.append(new TurnoutWN().html()); tiles.append(new TurnoutSW().html()); tiles.append(new Eraser().html()); return new Tag("div").clazz("list").content(tiles.toString()).addTo(tileMenu);