Index: /trunk/src/org/openstreetmap/josm/actions/JoinNodeWayAction.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/actions/JoinNodeWayAction.java	(revision 7130)
+++ /trunk/src/org/openstreetmap/josm/actions/JoinNodeWayAction.java	(revision 7131)
@@ -1,38 +1,62 @@
 //License: GPL. For details, see LICENSE file.
 package org.openstreetmap.josm.actions;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.command.ChangeCommand;
+import org.openstreetmap.josm.command.Command;
+import org.openstreetmap.josm.command.MoveCommand;
+import org.openstreetmap.josm.command.SequenceCommand;
+import org.openstreetmap.josm.data.coor.EastNorth;
+import org.openstreetmap.josm.data.osm.Node;
+import org.openstreetmap.josm.data.osm.OsmPrimitive;
+import org.openstreetmap.josm.data.osm.Way;
+import org.openstreetmap.josm.data.osm.WaySegment;
+import org.openstreetmap.josm.data.projection.Projections;
+import org.openstreetmap.josm.tools.Geometry;
+import org.openstreetmap.josm.tools.MultiMap;
+import org.openstreetmap.josm.tools.Shortcut;
+
+import java.awt.event.ActionEvent;
+import java.awt.event.KeyEvent;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.TreeSet;
 
 import static org.openstreetmap.josm.gui.help.HelpUtil.ht;
 import static org.openstreetmap.josm.tools.I18n.tr;
 
-import java.awt.event.ActionEvent;
-import java.awt.event.KeyEvent;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-
-import org.openstreetmap.josm.Main;
-import org.openstreetmap.josm.command.ChangeCommand;
-import org.openstreetmap.josm.command.Command;
-import org.openstreetmap.josm.command.SequenceCommand;
-import org.openstreetmap.josm.data.osm.Node;
-import org.openstreetmap.josm.data.osm.OsmPrimitive;
-import org.openstreetmap.josm.data.osm.Way;
-import org.openstreetmap.josm.data.osm.WaySegment;
-import org.openstreetmap.josm.tools.Shortcut;
-
 public class JoinNodeWayAction extends JosmAction {
 
+    protected final boolean joinWayToNode;
+
+    protected JoinNodeWayAction(boolean joinWayToNode, String name, String iconName, String tooltip, Shortcut shortcut, boolean registerInToolbar) {
+        super(name, iconName, tooltip, shortcut, registerInToolbar);
+        this.joinWayToNode = joinWayToNode;
+    }
+
     /**
-     * Constructs a new {@code JoinNodeWayAction}.
+     * Constructs a Join Node to Way action.
      */
-    public JoinNodeWayAction() {
-        super(tr("Join Node to Way"), "joinnodeway", tr("Include a node into the nearest way segments"),
+    public static JoinNodeWayAction createJoinNodeToWayAction() {
+        JoinNodeWayAction action = new JoinNodeWayAction(false,
+                tr("Join Node to Way"), "joinnodeway", tr("Include a node into the nearest way segments"),
                 Shortcut.registerShortcut("tools:joinnodeway", tr("Tool: {0}", tr("Join Node to Way")), KeyEvent.VK_J, Shortcut.DIRECT), true);
-        putValue("help", ht("/Action/JoinNodeWay"));
+        action.putValue("help", ht("/Action/JoinNodeWay"));
+        return action;
+    }
+
+    /**
+     * Constructs a Move Node onto Way action.
+     */
+    public static JoinNodeWayAction createMoveNodeOntoWayAction() {
+        JoinNodeWayAction action = new JoinNodeWayAction(true,
+                tr("Move Node onto Way"), "movewayontonode", tr("Move the node onto the nearest way segments and include it"),
+                null, true);
+        return action;
     }
 
@@ -45,5 +69,5 @@
         if (selectedNodes.size() != 1) return;
 
-        Node node = selectedNodes.iterator().next();
+        final Node node = selectedNodes.iterator().next();
 
         Collection<Command> cmds = new LinkedList<>();
@@ -53,50 +77,45 @@
                 !getCurrentDataSet().getSelectedWays().isEmpty();
 
-            List<WaySegment> wss = Main.map.mapView.getNearestWaySegments(
-                    Main.map.mapView.getPoint(node), OsmPrimitive.isSelectablePredicate);
-            HashMap<Way, List<Integer>> insertPoints = new HashMap<>();
-            for (WaySegment ws : wss) {
-                // Maybe cleaner to pass a "isSelected" predicate to getNearestWaySegments, but this is less invasive.
-                if(restrictToSelectedWays && !ws.way.isSelected()) {
-                    continue;
-                }
-
-                List<Integer> is;
-                if (insertPoints.containsKey(ws.way)) {
-                    is = insertPoints.get(ws.way);
-                } else {
-                    is = new ArrayList<>();
-                    insertPoints.put(ws.way, is);
-                }
-
-                if (ws.way.getNode(ws.lowerIndex) != node
-                        && ws.way.getNode(ws.lowerIndex+1) != node) {
-                    is.add(ws.lowerIndex);
-                }
+        List<WaySegment> wss = Main.map.mapView.getNearestWaySegments(
+                Main.map.mapView.getPoint(node), OsmPrimitive.isSelectablePredicate);
+        MultiMap<Way, Integer> insertPoints = new MultiMap<>();
+        for (WaySegment ws : wss) {
+            // Maybe cleaner to pass a "isSelected" predicate to getNearestWaySegments, but this is less invasive.
+            if (restrictToSelectedWays && !ws.way.isSelected()) {
+                continue;
             }
 
-            for (Map.Entry<Way, List<Integer>> insertPoint : insertPoints.entrySet()) {
-                List<Integer> is = insertPoint.getValue();
-                if (is.isEmpty()) {
-                    continue;
+            if (ws.getFirstNode() != node && ws.getSecondNode() != node) {
+                insertPoints.put(ws.way, ws.lowerIndex);
+            }
+        }
+
+        for (Map.Entry<Way, Set<Integer>> entry : insertPoints.entrySet()) {
+            final Way w = entry.getKey();
+            final Set<Integer> insertPointsForWay = entry.getValue();
+            if (insertPointsForWay.isEmpty()) {
+                continue;
+            }
+
+            List<Node> nodesToAdd = w.getNodes();
+            for (int i : pruneSuccsAndReverse(insertPointsForWay)) {
+                if (joinWayToNode) {
+                    EastNorth newPosition = Geometry.closestPointToSegment(
+                            w.getNode(i).getEastNorth(), w.getNode(i + 1).getEastNorth(), node.getEastNorth());
+                    cmds.add(new MoveCommand(node, Projections.inverseProject(newPosition)));
                 }
-
-                Way w = insertPoint.getKey();
-                List<Node> nodesToAdd = w.getNodes();
-                pruneSuccsAndReverse(is);
-                for (int i : is) {
-                    nodesToAdd.add(i+1, node);
-                }
-                Way wnew = new Way(w);
-                wnew.setNodes(nodesToAdd);
-                cmds.add(new ChangeCommand(w, wnew));
+                nodesToAdd.add(i + 1, node);
             }
-            if (cmds.isEmpty()) return;
-            Main.main.undoRedo.add(new SequenceCommand(tr("Join Node and Line"), cmds));
-            Main.map.repaint();
+            Way wnew = new Way(w);
+            wnew.setNodes(nodesToAdd);
+            cmds.add(new ChangeCommand(w, wnew));
+        }
+        if (cmds.isEmpty()) return;
+        Main.main.undoRedo.add(new SequenceCommand(getValue(NAME).toString(), cmds));
+        Main.map.repaint();
     }
 
-    private static void pruneSuccsAndReverse(List<Integer> is) {
-        HashSet<Integer> is2 = new HashSet<>();
+    private static SortedSet<Integer> pruneSuccsAndReverse(Collection<Integer> is) {
+        SortedSet<Integer> is2 = new TreeSet<>(Collections.reverseOrder());
         for (int i : is) {
             if (!is2.contains(i - 1) && !is2.contains(i + 1)) {
@@ -104,8 +123,5 @@
             }
         }
-        is.clear();
-        is.addAll(is2);
-        Collections.sort(is);
-        Collections.reverse(is);
+        return is2;
     }
 
Index: /trunk/src/org/openstreetmap/josm/gui/MainMenu.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/MainMenu.java	(revision 7130)
+++ /trunk/src/org/openstreetmap/josm/gui/MainMenu.java	(revision 7131)
@@ -248,5 +248,7 @@
     public final MergeNodesAction mergeNodes = new MergeNodesAction();
     /** Tools / Join Node to Way */
-    public final JoinNodeWayAction joinNodeWay = new JoinNodeWayAction();
+    public final JoinNodeWayAction joinNodeWay = JoinNodeWayAction.createJoinNodeToWayAction();
+    /** Tools / Join Way to Node */
+    public final JoinNodeWayAction moveNodeOntoWay = JoinNodeWayAction.createMoveNodeOntoWayAction();
     /** Tools / Disconnect Node from Way */
     public final UnJoinNodeWayAction unJoinNodeWay = new UnJoinNodeWayAction();
@@ -737,4 +739,5 @@
         add(toolsMenu, mergeNodes);
         add(toolsMenu, joinNodeWay);
+        add(toolsMenu, moveNodeOntoWay);
         add(toolsMenu, unJoinNodeWay);
         add(toolsMenu, unglueNodes);
