Coming Up for Air

JavaFX and AsciiDoctor: a Quick and Dirty Hack

You may or may not have noticed ([1], [2]), but I’ve been spending a lot of time with AsciiDoc lately. While it might simply be a case of noticing what you’re thinking about, it seems the tool has been gaining more and more momentum. From AsciiDoctor to Awestruct, to Jason Porter’s Maven plugin, it seems to be everywhere. At any rate, in need of a break, I wondered if I could leverage AsciiDoctor’s Java integration library and JavaFX to make a simple editor. It’s basic and ugly, but here’s what I have.

To start, let’s create a basic JavaFX application. To do this, I made use of the built-in JavaFX support in NetBeans 7.3 by clicking FileNew Project…​JavaFXJavaFX FXML Application. I entered all of the appropriate information in the rest of the wizard, and I had my empty application. The next step was to remove all of the default/example controls in the app and create the user interface I wanted. To do this, I used the Early Access build of Scene Builder 1.1. This isn’t meant to be a Scene Builder tutorial, so I’ll leave out the details and just give you the resulting FXML file:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
<?xml version="1.0" encoding="UTF-8"?>

<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.web.*?>

<AnchorPane xmlns:fx="http://javafx.com/fxml"
            fx:controller="com.steeplesoft.doctorfx.DoctorFXController"
            id="AnchorPane"
            prefHeight="600.0"
            prefWidth="800.0" >
    <children>
        <SplitPane dividerPositions="0.5"
                   focusTraversable="true"
                   prefHeight="200.0"
                   prefWidth="320.0"
                   AnchorPane.bottomAnchor="0.0"
                   AnchorPane.leftAnchor="0.0"
                   AnchorPane.rightAnchor="0.0"
                   AnchorPane.topAnchor="0.0">
            <items>
                <AnchorPane minHeight="0.0"
                            minWidth="0.0"
                            prefHeight="160.0"
                            prefWidth="100.0">
                    <children>
                        <TextArea fx:id="editField"
                                  onKeyTyped="#handleKeyTyped"
                                  prefHeight="198.0"
                                  prefWidth="116.0"
                                  wrapText="true"
                                  AnchorPane.bottomAnchor="0.0"
                                  AnchorPane.leftAnchor="0.0"
                                  AnchorPane.rightAnchor="0.0"
                                  AnchorPane.topAnchor="0.0" />
                    </children>
                </AnchorPane>
                <AnchorPane minHeight="0.0"
                            minWidth="0.0"
                            prefHeight="160.0"
                            prefWidth="100.0">
                    <children>
                        <WebView fx:id="preview"
                                 prefHeight="598.0"
                                 prefWidth="436.0"
                                 AnchorPane.bottomAnchor="0.0"
                                 AnchorPane.leftAnchor="0.0"
                                 AnchorPane.rightAnchor="0.0"
                                 AnchorPane.topAnchor="0.0" />
                    </children>
                </AnchorPane>
            </items>
        </SplitPane>
    </children>
</AnchorPane>

There’s a really good chance this is a bad pretty bad example, but I’m not JavaFX expert, so this is all I have for you. :) Next up, the Java controller class:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public class DoctorFXController implements Initializable {
    private final Asciidoctor instance;
    private Map<String, Object> options;
    @FXML
    TextArea editField;
    @FXML
    WebView preview;

    public DoctorFXController() {
        options = OptionsBuilder.options()
                .compact(false)
                .headerFooter(true)
                .safe(SafeMode.UNSAFE)
                .backend("html")
                .asMap();
        instance = Asciidoctor.Factory.create();
    }

    @FXML
    protected void handleKeyTyped(KeyEvent event) {
        preview.getEngine().loadContent(instance.render(editField.getText(), options));
    }

    @Override
    public void initialize(URL url, ResourceBundle rb) {
    }
}

Again, this probably sub-optimal code, but I’m dealing with a couple of APIs I don’t know all that well at the moment (this is a good example of "Release early. Release often" ;), so don’t get too hung up on things. When you run this application, you should see something like this:

doctorfx

It’s not very pretty, but it "works". As you type on the left, the pane on the right is constantly updated, which is kinda cool. :P

Currently, JavaFX builds are Ant-based and, to be honest, I really don’t want to muck around in that too much, so I just copied the AsciiDoc-related dependencies from Jason Porter’s Maven plugin and added those manually to the NetBeans project build path:

  • asciidoctor-java-integration-0.1.2.jar

  • jruby-complete-1.7.3.jar

Perhaps once the JavaFX migrates the build system to Gradle, this can be made a bit prettier. For now, for a Q&D PoC app, it works just fine.

The app clearly has a lot of work left. For example, note the period and the empty line at the top of the edit area. Without that, the first two lines of AsciiDoc markup are not rendered at all. If I change `= Hello, AsciiDoc` to `== Hello, AsciiDoc`, though, it renders just fine. I'm still trying to track that down. The app could also use some support (and related menus) for opening, saving, various edit actions, etc. For an hour’s worth of hacking, though, it’s not too shabby. My main interesting in this, though, was an excuse to play with the AsciiDoctor Java integration and JavaFX, and this let me do both at the same time.

As I have time and energy, I’ll probably keep hacking on this. In time, a usable editor might just come of it. :)

Quotes

Sample quote

Quote source