4.3.6. Accessing content

To show the principle of accessing data stored in a product, we implement a plug-in that allows a user to replace the obsolete <center> tag by the <div> tag for a selected node. To provide this functionality a new menu item named "Replace <center>" shall be available in the "Extra" sub-menu. When the user clicks this menu item, the content of the selected node shall be processed. If the content contains one or more <center>...</center> tags, then these tags shall be replaced by <div class="centered">...</div> tags. Following plug-in realizes this functionality:
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 
package myexample;
 
import org.docma.plugin.*;
import org.docma.plugin.web.*;
 
public class ReplaceCenterPlugin extends DefaultWebPlugin
implements UIListener {
 
private final String my_item_id = "my_plugin_menu_item";
@Override
public void onInitMainWindow(WebPluginContext ctx,
WebUserSession webSess)
{
String item_label = webSess.getLabel("my_plugin.replace_center");
String icon_url = "plugins/my_plugin/images/my_icon.png";
webSess.addMenuItem(ctx, "treemenuExtra", my_item_id,
item_label, icon_url, null, false);
webSess.setUIListener(ctx, this);
}
 
@Override
public void onEvent(UIEvent evt)
{
WebUserSession webSess = evt.getSession();
String targetId = evt.getTargetId();
if (("treemenu".equals(targetId)) && evt.isOpen()) {
int cnt = webSess.selectedNodesCount();
webSess.setMenuDisabled(my_item_id, cnt != 1);
} else if (my_item_id.equals(targetId) && evt.isClick()) {
Node nd = webSess.getSingleSelectedNode(true);
if (nd instanceof PubContent) {
replaceCenter((PubContent) nd);
}
}
}
 
private void replaceCenter(PubContent cont)
{
String html_old = cont.getContentString();
String html_new = html_old.
replaceAll("<center[^>]*>",
"<div class=\"centered\">").
replaceAll("</center>",
"</div>");
if (! html_new.equals(html_old)) {
cont.makeRevision();
cont.setContentString(html_new);
}
}
}

Listing 4.3.22.

The plug-in shown above is similar to the Hello World plugin-in described in Section 4.3.2, “Adding menu items” . The lines in the listing above that differ from the Hello World plug-in are highlighted. The onInitMainWindow method is identical, except that the label identifier for the menu item has been changed to "my_plugin.replace_center". As a consequence, the locale.properties file has to be adapted to contain following line:

my_plugin.replace_center = Replace <center>

Listing 4.3.23.

The main functionality is in the onEvent method. If a click event is detected and only a single node is selected, then the currently selected node is retrieved by the line
Node nd = webSess.getSingleSelectedNode(true);
The argument true specifies that an error message shall be displayed in case no single node is selected. The next line checks whether the returned node implements the org.docma.plugin.PubContent interface. In Docmenta all XHTML content nodes implement this interface. This way it is possible to distinguish XHTML content nodes from other nodes (for example image or folder nodes). If the node is an XHTML content node, then the line
String html_old = cont.getContentString();
retrieves the XHTML content of the node and stores it in the variable html_old. The next statement searches in the variable html_old for all occurences of <center …> and replaces them by <div class="centered">. Additionally, all occurences of the closing </center> tag are replaced by </div>. The result is stored in the variable html_new. Note that if html_old contains no <center> tags, then html_new is identical to html_old. In this case nothing is done. Otherwise the lines
cont.makeRevision();
cont.setContentString(html_new);
create a new revision of the content and assign the modified content to the node.
You can install the plug-in and test it by choosing the added menu item from the context menu of a selected content node. If the content node contains a <center> tag, it will be replaced by the <div class="centered"> tag. To define the formatting of these <div> blocks, you have to create a style with ID "centered" and assign CSS properties to it.
We can further improve the plug-in by allowing selection of multiple nodes. As you might guess, the method getSingleSelectedNode, which is used in the listing above, is only suitable to retrieve a single selected node. If more than one node is selected by the user, this method returns null (and if the argument true is passed, an error message is shown). To retrieve multiple selected nodes, the method getSelectedSiblingNodes has to be used instead. Furthermore, the menu item should only be disabled in case not all selected nodes are XHTML content nodes.
All this can be achieved by changing the onEvent method as follows:
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 
public void onEvent(UIEvent evt)
{
WebUserSession webSess = evt.getSession();
String targetId = evt.getTargetId();
if (("treemenu".equals(targetId)) && evt.isOpen()) {
Node[] nds = webSess.getSelectedSiblingNodes(true);
boolean enabled = (nds != null) && (nds.length > 0);
if (nds != null) {
for (Node nd : nds) {
if (! (nd instanceof PubContent)) {
enabled = false;
break;
}
}
}
webSess.setMenuDisabled(my_item_id, enabled);
} else if (my_item_id.equals(targetId) && evt.isClick()) {
Node[] nds = webSess.getSelectedSiblingNodes(true);
if (nds != null) {
for (Node nd : nds) {
if (nd instanceof PubContent) {
replaceCenter((PubContent) nd);
}
}
}
}
}

Listing 4.3.24.

Be aware that the method getSelectedSiblingNodes only allows selection of nodes that have the same parent node. Otherwise this method returns null (and if the argument true is passed, an error message is shown).