diff --git a/src/main/java/net/rptools/maptool/client/MapToolLineParser.java b/src/main/java/net/rptools/maptool/client/MapToolLineParser.java index 9303dc7cb0..612a552907 100644 --- a/src/main/java/net/rptools/maptool/client/MapToolLineParser.java +++ b/src/main/java/net/rptools/maptool/client/MapToolLineParser.java @@ -1438,7 +1438,9 @@ public String parseLine( frameName, false, false, frameOpts, expressionBuilder.toString()); break; case OVERLAY: - MapTool.getFrame().getHtmlOverlay().updateContents(expressionBuilder.toString()); + MapTool.getFrame() + .getHtmlOverlay() + .updateContents(expressionBuilder.toString(), true); break; case CHAT: builder.append(expressionBuilder); diff --git a/src/main/java/net/rptools/maptool/client/ui/htmlframe/HTMLDialog.java b/src/main/java/net/rptools/maptool/client/ui/htmlframe/HTMLDialog.java index 0ba10ec5e0..f6946c126f 100644 --- a/src/main/java/net/rptools/maptool/client/ui/htmlframe/HTMLDialog.java +++ b/src/main/java/net/rptools/maptool/client/ui/htmlframe/HTMLDialog.java @@ -175,6 +175,7 @@ public void addHTMLPanel(boolean scrollBar, boolean isHTML5) { * @param input whether submitting the form closes it * @param temp whether the frame is temporary * @param closeButton whether the close button is to be displayed + * @param scrollReset whether the scrollbar should be reset * @param isHTML5 whether the frame should support HTML5 * @param value a value to be returned by getDialogProperties() * @param html the HTML to display in the dialog @@ -189,6 +190,7 @@ static HTMLDialog showDialog( boolean input, boolean temp, boolean closeButton, + boolean scrollReset, boolean isHTML5, Object value, String html) { @@ -199,7 +201,8 @@ static HTMLDialog showDialog( dialog = new HTMLDialog(MapTool.getFrame(), name, frame, width, height, isHTML5); dialogs.put(name, dialog); } - dialog.updateContents(html, title, frame, input, temp, closeButton, isHTML5, value); + dialog.updateContents( + html, title, frame, input, temp, closeButton, scrollReset, isHTML5, value); // dialog.canResize = false; if (!dialog.isVisible()) { @@ -307,6 +310,7 @@ public static void doTokenChanged(Token token) { * @param input whether to close the dialog on form submit * @param temp whether to make the dialog temporary * @param closeButton whether to show a close button + * @param scrollReset whether the scrollbar should be reset * @param isHTML5 whether to make the dialog HTML5 (JavaFX) * @param val the value held in the frame */ @@ -317,6 +321,7 @@ private void updateContents( boolean input, boolean temp, boolean closeButton, + boolean scrollReset, boolean isHTML5, Object val) { if (this.isHTML5 != isHTML5) { @@ -336,7 +341,7 @@ private void updateContents( this.setTitle(title); macroCallbacks.clear(); updateButton(closeButton); - panel.updateContents(html); + panel.updateContents(html, scrollReset); } /** diff --git a/src/main/java/net/rptools/maptool/client/ui/htmlframe/HTMLFrame.java b/src/main/java/net/rptools/maptool/client/ui/htmlframe/HTMLFrame.java index f4ec50665a..4bbac50fc8 100644 --- a/src/main/java/net/rptools/maptool/client/ui/htmlframe/HTMLFrame.java +++ b/src/main/java/net/rptools/maptool/client/ui/htmlframe/HTMLFrame.java @@ -97,6 +97,7 @@ static void close(String name) { * @param width the width of the frame in pixels. * @param height the height of the frame in pixels. * @param temp whether the frame should be temporary. + * @param scrollReset whether the scrollbar should be reset. * @param isHTML5 whether it should use HTML5 (JavaFX) or HTML 3.2 (Swing). * @param val a value that can be returned by getFrameProperties(). * @param html the html to display in the frame. @@ -109,6 +110,7 @@ public static HTMLFrame showFrame( int width, int height, boolean temp, + boolean scrollReset, boolean isHTML5, Object val, String html) { @@ -129,7 +131,7 @@ public static HTMLFrame showFrame( // Jamz: why undock frames to center them? if (!frame.isDocked()) center(name); } - frame.updateContents(html, title, tabTitle, temp, isHTML5, val); + frame.updateContents(html, title, tabTitle, temp, scrollReset, isHTML5, val); return frame; } @@ -225,11 +227,18 @@ public static void center(String name) { * @param title the title of the frame * @param tabTitle the tabTitle of the frame * @param temp whether the frame is temporary + * @param scrollReset whether the scrollbar should be reset * @param isHTML5 whether the frame should support HTML5 (JavaFX) * @param val the value to put in the frame */ public void updateContents( - String html, String title, String tabTitle, boolean temp, boolean isHTML5, Object val) { + String html, + String title, + String tabTitle, + boolean temp, + boolean scrollReset, + boolean isHTML5, + Object val) { if (this.isHTML5 != isHTML5) { this.isHTML5 = isHTML5; panel.removeFromContainer(this); // remove previous panel @@ -241,7 +250,7 @@ public void updateContents( setTabTitle(tabTitle); setTemporary(temp); setValue(val); - panel.updateContents(html); + panel.updateContents(html, scrollReset); } /** Run all callback macros for "onChangeSelection". */ diff --git a/src/main/java/net/rptools/maptool/client/ui/htmlframe/HTMLFrameFactory.java b/src/main/java/net/rptools/maptool/client/ui/htmlframe/HTMLFrameFactory.java index 035a4433a2..74ae03d791 100644 --- a/src/main/java/net/rptools/maptool/client/ui/htmlframe/HTMLFrameFactory.java +++ b/src/main/java/net/rptools/maptool/client/ui/htmlframe/HTMLFrameFactory.java @@ -52,6 +52,7 @@ public static void show( Object frameValue = null; boolean hasFrame = true; boolean closeButton = true; + boolean scrollReset = false; if (properties != null && !properties.isEmpty()) { String[] opts = properties.split(";"); @@ -113,6 +114,10 @@ public static void show( } catch (NumberFormatException e) { // Ignoring the value; shouldn't we warn the user? } + } else if (keyLC.equals("scrollreset")) { + if (Integer.parseInt(value) == 1) { + scrollReset = true; + } } else if (keyLC.equals("value")) { frameValue = value; } else if (keyLC.equals("tabtitle")) { @@ -123,7 +128,7 @@ public static void show( if (tabTitle == null) tabTitle = title; // if tabTitle not set, make it same as title if (isFrame) { HTMLFrame.showFrame( - name, title, tabTitle, width, height, temporary, isHTML5, frameValue, html); + name, title, tabTitle, width, height, temporary, scrollReset, isHTML5, frameValue, html); } else { HTMLDialog.showDialog( name, @@ -134,6 +139,7 @@ public static void show( input, temporary, closeButton, + scrollReset, isHTML5, frameValue, html); diff --git a/src/main/java/net/rptools/maptool/client/ui/htmlframe/HTMLJFXPanel.java b/src/main/java/net/rptools/maptool/client/ui/htmlframe/HTMLJFXPanel.java index 55347c7152..5877e99039 100644 --- a/src/main/java/net/rptools/maptool/client/ui/htmlframe/HTMLJFXPanel.java +++ b/src/main/java/net/rptools/maptool/client/ui/htmlframe/HTMLJFXPanel.java @@ -64,6 +64,13 @@ public class HTMLJFXPanel extends JFXPanel implements HTMLPanelInterface { /** The WebEngine of the WebView. */ private WebEngine webEngine; + /** Whether the scrolling should be reset. */ + private boolean scrollReset = true; + /** The horizontal scrolling. */ + private int scrollX = 0; + /** The vertical scrolling. */ + private int scrollY = 0; + /** The bridge from Javascript to Java. */ private static final JavaBridge bridge = new JavaBridge(); @@ -180,12 +187,17 @@ public void flush() { } @Override - public void updateContents(final String html) { + public void updateContents(final String html, boolean scrollReset) { if (log.isDebugEnabled()) { log.debug("setting text in WebView: " + html); } Platform.runLater( () -> { + this.scrollReset = scrollReset; + if (!scrollReset) { + scrollX = getHScrollValue(); + scrollY = getVScrollValue(); + } webEngine.loadContent(SCRIPT_BLOCK_EXT + HTMLPanelInterface.fixHTML(html)); }); } @@ -357,6 +369,11 @@ void handlePage() { EventTarget target = (EventTarget) nodeList.item(i); target.addEventListener("click", listenerSubmit, false); } + + // Restores the previous scrolling. + if (!scrollReset) { + scrollTo(scrollX, scrollY); + } } } @@ -591,4 +608,24 @@ private void doSubmit(String method, String action, String data) { new HTMLActionEvent.FormActionEvent(this, method, action, data)); } } + + /** Returns the vertical scroll value, i.e. thumb position. */ + private int getVScrollValue() { + return (Integer) webEngine.executeScript("document.body.scrollTop"); + } + + /** Returns the horizontal scroll value, i.e. thumb position. */ + private int getHScrollValue() { + return (Integer) webEngine.executeScript("document.body.scrollLeft"); + } + + /** + * Scrolls the WebView. + * + * @param x the horizontal scrolling + * @param y the vertical scrolling + */ + private void scrollTo(int x, int y) { + webEngine.executeScript("window.scrollTo(" + x + ", " + y + ")"); + } } diff --git a/src/main/java/net/rptools/maptool/client/ui/htmlframe/HTMLOverlay.java b/src/main/java/net/rptools/maptool/client/ui/htmlframe/HTMLOverlay.java index 57843e4615..c262595bfb 100644 --- a/src/main/java/net/rptools/maptool/client/ui/htmlframe/HTMLOverlay.java +++ b/src/main/java/net/rptools/maptool/client/ui/htmlframe/HTMLOverlay.java @@ -296,9 +296,9 @@ public void actionPerformed(ActionEvent e) { } @Override - public void updateContents(final String html) { + public void updateContents(final String html, boolean scrollReset) { macroCallbacks.clear(); // clear the old callbacks - super.updateContents(html); + super.updateContents(html, true); getDropTarget().setActive(false); // disables drop on overlay, drop goes to map if ("".equals(html)) { closeRequest(); // turn off the overlay diff --git a/src/main/java/net/rptools/maptool/client/ui/htmlframe/HTMLPane.java b/src/main/java/net/rptools/maptool/client/ui/htmlframe/HTMLPane.java index ee568a94b5..e5c65bd980 100644 --- a/src/main/java/net/rptools/maptool/client/ui/htmlframe/HTMLPane.java +++ b/src/main/java/net/rptools/maptool/client/ui/htmlframe/HTMLPane.java @@ -26,6 +26,7 @@ import javax.swing.*; import javax.swing.event.HyperlinkEvent; import javax.swing.event.HyperlinkListener; +import javax.swing.text.DefaultCaret; import javax.swing.text.MutableAttributeSet; import javax.swing.text.html.HTML; import javax.swing.text.html.HTMLDocument; @@ -121,13 +122,17 @@ public void setEditorKitDefaultCursor(Cursor cursor) { * Flush the pane, set the new html, and set the caret to zero. * * @param html the html to set + * @param scrollReset whether the scrollbar should be reset */ - public void updateContents(final String html) { + public void updateContents(final String html, boolean scrollReset) { EventQueue.invokeLater( - new Runnable() { - public void run() { - editorKit.flush(); - setText(html); + () -> { + DefaultCaret caret = (DefaultCaret) getCaret(); + caret.setUpdatePolicy( + scrollReset ? DefaultCaret.UPDATE_WHEN_ON_EDT : DefaultCaret.NEVER_UPDATE); + editorKit.flush(); + setText(html); + if (scrollReset) { setCaretPosition(0); } }); diff --git a/src/main/java/net/rptools/maptool/client/ui/htmlframe/HTMLPanel.java b/src/main/java/net/rptools/maptool/client/ui/htmlframe/HTMLPanel.java index f3b9cb6b1a..fa7571f1b6 100644 --- a/src/main/java/net/rptools/maptool/client/ui/htmlframe/HTMLPanel.java +++ b/src/main/java/net/rptools/maptool/client/ui/htmlframe/HTMLPanel.java @@ -45,7 +45,7 @@ public class HTMLPanel extends JPanel implements HTMLPanelInterface { } else { add(pane, BorderLayout.CENTER); } - updateContents(""); + updateContents("", false); // ESCAPE closes the window pane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW) @@ -60,14 +60,9 @@ public void actionPerformed(ActionEvent e) { }); } - /** - * Update the contents of the panel. - * - * @param html The HTML to display. - */ @Override - public void updateContents(final String html) { - pane.updateContents(html); + public void updateContents(final String html, boolean scrollReset) { + pane.updateContents(html, scrollReset); } /** Flushes any caching for the panel. */ diff --git a/src/main/java/net/rptools/maptool/client/ui/htmlframe/HTMLPanelInterface.java b/src/main/java/net/rptools/maptool/client/ui/htmlframe/HTMLPanelInterface.java index 628a7ff00e..cab95427e7 100644 --- a/src/main/java/net/rptools/maptool/client/ui/htmlframe/HTMLPanelInterface.java +++ b/src/main/java/net/rptools/maptool/client/ui/htmlframe/HTMLPanelInterface.java @@ -23,8 +23,9 @@ interface HTMLPanelInterface { * Update the HTML content and the close button. * * @param html the html to load. + * @param scrollreset whether the scroll bar should be reset. */ - void updateContents(final String html); + void updateContents(final String html, boolean scrollreset); /** Flush the Panel. */ void flush();