Tutorial: Custom Components for Hyperlink Dialog

EditLive!’s “Hyperlink” dialog consists of a set of panels, used to insert hyperlinks from different sources. EditLive! allows you to customize this dialog, by adding your own custom panels. This can be done using the EditLive! Swing SDK, or as an Advanced API plugin.

For this example, I’ll be creating a custom panel plugin which lets you change the “id” and “class” of a hyperlink. Note: due to the design of the hyperlink dialog, these attributes will only be saved if this panel is active when the user clicks ok.

The key parts are:

  1. Creating the plugin and registering with EditLive!.
  2. Creating the panel.
  3. Writing the new attributes on save.
  4. Reading the existing link’s attributes on load.

1. Creating the plugin and registering with EditLive!

Firstly, we need a basic Advanced API plugin class. This involves creating a class which takes an ELJBean in its constructor. To actually load the plugin, there are other steps required, which are described in the EditLive! documentation. There are also previous LiveWorks! articles to help: Using Plugins To Extend EditLive! and Initializing Background Loading Plugins.

public class CustomPanel {
        public CustomPanel(ELJBean bean) {
        }
}

Next, we need a class which implements the HyperlinkDialogComponent interface in the Advanced API.  We might as well add this to the current class, as it’s not doing much else. For the moment, just provide dummy implementations for the interface’s methods (“Override/Implement Methods” in Eclipse).

public class CustomPanel implements HyperlinkDialogComponent {
...
}

To register this component as a hyperlink dialog, call the “addHyperlinkDialogComponent” bean method. We’ll do this in the constructor. The first parameter is the class that the Hyperlink dialog instantiates to create the custom panel.  In our instance, we’re adding the current class. I’ll discuss the second parameter in a minute.

public CustomPanel(ELJBean bean) {
        bean.addHyperlinkDialogComponent(this.getClass(), new Object[] { bean });
}

Now, when the hyperlink dialog instantiates a custom component, it looks for a constructor which takes an Object[] as its only parameter. So, we will need another constructor in our CustomPanel class.

private ELJBean bean;  
public CustomPanel(Object[] params) {
        this.bean = (ELJBean)params[0];
}

The Object array allows us to pass parameters through from the plugin to the custom panel. In this case, we’re passing a reference to the bean, which we’ll use later. Note that this class is instantiated twice – once as a plugin, and once as a dialog component. In real code it would probably be better to use a separate class for each role to avoid confusion.

2. Creating the panel

Now the framework is in place, its time to implement the HyperlinkDialogComponent methods. Let’s start with the getJComponent() method, which provides the actual panel displayed in the hyperlink dialog. For this example, I’ll use a simple form which asks for the “id” and “class” of the link.

public JComponent getJComponent() {
        panel = new JPanel(new BorderLayout());
        subPanel = new JPanel(new GridLayout(2, 2));
        panel.add(subPanel, BorderLayout.NORTH);
        panel.add(Box.createGlue());  
        subPanel.add(new JLabel("id"));
        idField = new JTextField();
        subPanel.add(idField);
        subPanel.add(new JLabel("class"));
        classField = new JTextField();
        subPanel.add(classField);
        return panel;
}

If you load the plugin now, it should display the panel, but the button to activate the panel will be blank. We can specify these with the getButtonImage() and getButtonText() functions. For simplicity, I’ll just leave the icon blank.

public ImageIcon getButtonImage() {
        return null;
}
public String getButtonText() {
        return "Advanced Link";
}

3. Writing the new attributes on save.

We now need to get the data from these fields into the actual hyperlink. This is done in the getAttributeMap method. This method gets an input of the current attributes of the link, including those from fields outside the switch panels (like the href, target and title). Add to this map, then return it.

I’ve also wrapped the map additions in a method which ensures the attribute is only in the map if its not blank which avoids adding redundant attributes to the HTML.

private void addIfSpecified(Map in, String name, String value) {
        if (!value.trim().isEmpty()) {
                in.put(name, value.trim());
        } else {
                in.remove(name);
        }
}

public Map getAttributeMap(Map in) {
        addIfSpecified(in, "id", idField.getText());
        addIfSpecified(in, "class", (String)classField.getText());
        return in;
}

4. Reading the existing link’s attributes on load.

At this stage, this panel will set the properties of the hyperlink, but if you edit an existing hyperlink, the custom panel’s fields will not display the current values. This is where we need the ELJBean object.

From the bean, we can get the HTMLPane object – this is the editing pane (JTextPane object) for the “design” view. We then call getInputAttributes to get the “a” element and its attributes. We can then populate our text fields with these attribute values.

private void setFieldFromAttribute(AttributeSet attrs, Object attribute, JTextField field) {
        Object value = attrs.getAttribute(attribute);          
        if (value != null) {
                field.setText(value.toString());
        }
}
public JComponent getJComponent() {
       …
       Object aTag = bean.getHTMLPane().getInputAttributes().getAttribute(HTML.Tag.A);
       if (aTag != null) {
                setFieldFromAttribute((AttributeSet)aTag, HTML.Attribute.CLASS, classField);
                setFieldFromAttribute((AttributeSet)aTag, HTML.Attribute.ID, idField);         
       }
       return panel;
}

There are 3 remaining interface methods which we don’t need for this example. They would be useful for things such as opening/closing connections to external systems.

public void setActive(boolean active) { }      
public void setHyperlinkDialog(HyperlinkDialog parent) { }
public void cleanUp() { }

Where to from here?

The custom panel is complete. Feel free to use this plugin as-is, or as a template for creating your own components.

This example sets special attributes of the hyperlink, however hyperlink dialog components could also be used to provide an integrated way of linking to existing content in a repository.

EditLive! also offers several alternatives for providing similar functionality.

With an Advanced API plugin, you could create an entire JDialog to replace the existing hyperlink dialog. Register this plugin as an EventListener, and listen for TextEvent.HYPERLINK_ACTION. When this event is triggered, display your dialog, then call event.setHandled(true) to prevent the built-in dialog from displaying. When the dialog closes, use the DocumentModifier methods (available from ELJBean.getDocumentModifier()) to edit the content.

Finally, a custom menu item or toolbar button can trigger a Javascript method, which you could use to pop up a new browser window which displays a specific URL containing the dialog. Then, you can use the “insertHTMLAtCursor” or “insertHyperlinkAtCursor” functions from our Javascript API to edit EditLive!’s content.

Download the Custom Hyperlink Dialog Plugin