I wrote a small JavaFX Application to inspect Javascript within HTML pages. It loads and browses sites, shows the HTML source, shows an overview of the text of a page, provides a simple Javascript terminal, and runs Javscript files from disk. I'm thinking with some careful perusing it can be at least a little shorter and more succinct. How can this implementation be enhanced?import java.io.File;import java.io.IOException;import java.nio.charset.Charset;import java.nio.file.Files;import java.nio.file.Paths;import java.util.ArrayList;import javafx.application.Application;import javafx.beans.value.ChangeListener;import javafx.beans.value.ObservableValue;import javafx.concurrent.Worker;import javafx.event.ActionEvent;import javafx.scene.Scene;import javafx.scene.control.Alert;import javafx.scene.control.Alert.AlertType;import javafx.scene.control.Menu;import javafx.scene.control.MenuBar;import javafx.scene.control.MenuItem;import javafx.scene.control.MenuItemBuilder;import javafx.scene.control.TextArea;import javafx.scene.control.TextField;import javafx.scene.input.KeyCode;import javafx.scene.input.KeyCodeCombination;import javafx.scene.input.KeyCombination;import javafx.scene.input.KeyEvent;import javafx.scene.layout.BorderPane;import javafx.scene.layout.GridPane;import javafx.scene.layout.Priority;import javafx.scene.web.WebEngine;import javafx.scene.web.WebView;import javafx.stage.FileChooser;import javafx.stage.Stage;public class Browser extends Application {    private static final String help =         + dir=function(x){        + rv=\\;        + Object.keys(x).forEach(function(key){        + rv+=key+\\\n\;        + });return rv;};        + dir(%s);;    @Override    public void start(Stage primaryStage) {        MenuBar menuBar = new MenuBar();        menuBar.setVisible(true);        Menu viewMenu = new Menu(Options);        menuBar.getMenus().addAll(viewMenu);        WebView webView = new WebView();        WebEngine eng = webView.getEngine();        eng.getLoadWorker().stateProperty().addListener(new ChangeListener<Worker.State>() {            @Override            public void changed(ObservableValue ov, Worker.State oldState, Worker.State newState) {                if (newState == Worker.State.SUCCEEDED) {                    primaryStage.setTitle(eng.getTitle());                }            }        });        final MenuItem viewContent            = MenuItemBuilder.create()            .text(Content)            .onAction((ActionEvent e) -> {                showText(Content of  + eng.getTitle(), primaryStage,                    (String) eng.executeScript(document.documentElement.innerText));            })            .accelerator(                new KeyCodeCombination(                    KeyCode.V, KeyCombination.ALT_DOWN))            .build();        final MenuItem viewSource            = MenuItemBuilder.create()            .text(Source)            .onAction((ActionEvent e) -> {                showText(Source of  + eng.getTitle(), primaryStage,                    (String) eng.executeScript(document.documentElement.outerHTML));            })            .accelerator(                new KeyCodeCombination(                    KeyCode.S, KeyCombination.ALT_DOWN))            .build();        final MenuItem console            = MenuItemBuilder.create()            .text(Console)            .onAction((ActionEvent e) -> {                console(primaryStage, eng);            })            .accelerator(                new KeyCodeCombination(                    KeyCode.C, KeyCombination.ALT_DOWN))            .build();        final MenuItem openScript            = MenuItemBuilder.create()            .text(Open Script)            .onAction((ActionEvent e) -> {                File file = new FileChooser().showOpenDialog(primaryStage);                if (file != null) {                    String result;                    try {                        result = (String)eng.executeScript(readFile(file.getCanonicalPath(),                            Charset.defaultCharset()));                    } catch (Exception ex) {                        result = ex.getMessage();                    }                    alert(Result, Final Value, Final Value of Script:, result);                }            })            .accelerator(                new KeyCodeCombination(                    KeyCode.O, KeyCombination.ALT_DOWN))            .build();        viewMenu.getItems().addAll(viewContent, viewSource, console, openScript);        TextField address = new TextField();        address.setOnKeyTyped((KeyEvent ke) -> {            String ch = ke.getCharacter();            switch (ch.getBytes()[0]) {                case 13:                    ke.consume();                    eng.load(address.getText());            }        });        BorderPane root = new BorderPane();        root.setTop(address);        root.setCenter(webView);        root.setBottom(menuBar);        Scene scene = new Scene(root, 800, 600);        primaryStage.setTitle();        primaryStage.setScene(scene);        primaryStage.show();    }    public static void main(String[] args) {        launch(args);    }    private void showText(String title, Stage primaryStage, String text) {        TextArea root = new TextArea(text);        Scene secondScene = new Scene(root, 600, 400);        Stage secondStage = new Stage();        secondStage.setTitle(title);        secondStage.setScene(secondScene);        secondStage.initOwner(primaryStage);        secondStage.show();    }    ArrayList<String> history = new ArrayList<>();    StringBuilder input = new StringBuilder();    private void console(Stage primaryStage, WebEngine eng) {        final String PROMPT = > ;        TextArea root = new TextArea(PROMPT);        root.setStyle(-fx-font-family: monospace);        root.setOnKeyTyped((KeyEvent ke) -> {            String ch = ke.getCharacter();            ke.consume();            switch (ch.getBytes()[0]) {                case 13:                    try {                        if (input.length() == 0 && history.size() > 0) {                            input = new StringBuilder(history.get(history.size() - 2).substring(PROMPT.length()));                            break;                        } else if (input.toString().contains( )                            && input.toString().split( )[0].equals(help)) {                            System.out.println(String.format(help, input.toString().split( )[1]));                            input = new StringBuilder(String.format(help, input.toString().split( )[1]));                        }                        history.add(PROMPT + input.toString());                        history.add(eng.executeScript(input.toString()).toString());                    } catch (Exception jse) {                        history.add(jse.toString());                    }                    input = new StringBuilder();                    break;                case 8:                    if (input.length() > 0) {                        input.setLength(input.length() - 1);                    }                    break;                default:                    input.append(ch);                    break;            }            root.setText();            // while (history.size() > 20) history.remove(0);            history.stream().forEach((entry) -> {                root.appendText(entry + \n);            });            root.appendText(PROMPT);            root.appendText(input.toString());            root.positionCaret(root.getLength());        });        Scene secondScene = new Scene(root, 600, 400);        Stage secondStage = new Stage();        secondStage.setTitle(Javascript Console);        secondStage.setScene(secondScene);        secondStage.initOwner(primaryStage);        secondStage.show();    }    static String readFile(String path, Charset encoding)        throws IOException {        byte[] encoded = Files.readAllBytes(Paths.get(path));        return new String(encoded, encoding);    }    private void alert(String title, String header, String content, String extra) {        Alert alert = new Alert(AlertType.INFORMATION);        alert.setTitle(title);        alert.setHeaderText(header);        alert.setContentText(content);        TextArea textArea = new TextArea(extra);        textArea.setEditable(false);        textArea.setWrapText(true);        textArea.setMaxWidth(Double.MAX_VALUE);        textArea.setMaxHeight(Double.MAX_VALUE);        GridPane.setVgrow(textArea, Priority.ALWAYS);        GridPane.setHgrow(textArea, Priority.ALWAYS);        GridPane expContent = new GridPane();        expContent.setMaxWidth(Double.MAX_VALUE);        expContent.add(textArea, 0, 1);        alert.getDialogPane().setExpandableContent(expContent);        alert.showAndWait();    }}Tip: you can type help document, for example; in the console window. This command will be auto-replaced with a short script to output a listing of document. When running scripts just remember this program tries to convert and diplay the last statement as a string. You can also press Enter at the console to replay the last input. Lastly, I want to present a script that displays links from a given page:var arr = [], l = document.links;for(var i=0; i<l.length; i++) {    arr.push(l[i].href);};print = function(item) {    document.write(<a href=\ + item + \> + item + </a><br>);    result += item + \n;}result = ;arr.forEach(print);resultThe project is available on github. Some screenshots:
Web Page Inspector
java;javascript;user interface;javafx
case 13:If you're going to add in hooks to keycodes like that, eitherUse the KeyCode class you were using earlierMake use of java's char to byte casting; use '\r'Define the value as a constant KEYCODE_CARRIAGE_RETURNAdd a comment // \r carriage return, enter key.I'd prefer 1 or 2.I also think it would be handy if these objects    final MenuItem viewContent        = MenuItemBuilder.create()        .text(Content)        .onAction((ActionEvent e) -> {            showText(Content of  + eng.getTitle(), primaryStage,                (String) eng.executeScript(document.documentElement.innerText));        })        .accelerator(            new KeyCodeCombination(                KeyCode.V, KeyCombination.ALT_DOWN))        .build();    final MenuItem viewSource        = MenuItemBuilder.create()        .text(Source)        .onAction((ActionEvent e) -> {            showText(Source of  + eng.getTitle(), primaryStage,                (String) eng.executeScript(document.documentElement.outerHTML));        })        .accelerator(            new KeyCodeCombination(                KeyCode.S, KeyCombination.ALT_DOWN))        .build();    final MenuItem console        = MenuItemBuilder.create()        .text(Console)        .onAction((ActionEvent e) -> {            console(primaryStage, eng);        })        .accelerator(            new KeyCodeCombination(                KeyCode.C, KeyCombination.ALT_DOWN))        .build();    final MenuItem openScript        = MenuItemBuilder.create()        .text(Open Script)        .onAction((ActionEvent e) -> {            File file = new FileChooser().showOpenDialog(primaryStage);            if (file != null) {                String result;                try {                    result = (String)eng.executeScript(readFile(file.getCanonicalPath(),                        Charset.defaultCharset()));                } catch (Exception ex) {                    result = ex.getMessage();                }                alert(Result, Final Value, Final Value of Script:, result);            }        })        .accelerator(            new KeyCodeCombination(                KeyCode.O, KeyCombination.ALT_DOWN))        .build();Were created each in their own function. Right now, populating the view is a messy place, and by stowing these elements into separate functions you can keep the menu items and the management of menu items apart.