I'm working on creating the Link menu on the Oxygen Web-Author, there is already having two menu's called "ulink" and "uri". When I include the third menu called xref, the functionality of xref is not working fine, It's taking "ulink" functionality in the oxygen framework.js.
var insertWebLinkActionId =
sync.docbook.DocbookExtension.prototype.version == 5 ? "insert.web.link" : "insert.web.ulink";
var originalInsertWebLinkAction = actionsManager.getActionById(insertWebLinkActionId);
if(originalInsertWebLinkAction) {
var webLinkOperationClass = sync.docbook.DocbookExtension.prototype.version == 5 ?
"ro.sync.ecss.extensions.docbook.link.InsertExternalLinkOperation" :
"ro.sync.ecss.extensions.docbook.link.InsertULink";
var insertWebLinkAction = new sync.actions.InsertWebLink(
originalInsertWebLinkAction,
webLinkOperationClass,
editor,
'url_value');
actionsManager.registerAction(insertWebLinkActionId, insertWebLinkAction);
}
Here they already inserted menu by using the above code, in that insert.web.link and insert.web.ulink represent the corresponding menu from the translation.xml
<key type="action" value="insert.web.ulink">
<comment>Insert Link action name.</comment>
<val lang="en_US">Web Link (ulink)...</val>
</key>
...
<key type="action" value="insert.cross.reference.xref">
<comment>Insert Link action name.</comment>
<val lang="en_US">Cross reference (xref)...</val>
</key>
So I want to insert the Xref menu to the javascript, the Xref menu and class path represent insert.cross.reference.xref and ro.sync.ecss.extensions.docbook.link.InsertXrefOperation correspondingly.
You can implement your own version of the "Insert Cross Reference (xref)" action in your DocBook framework extension. To do this you need to:
var DocBookCrossRefXrefAction = function (editor) {
sync.actions.AbstractAction.call(this);
this.editor = editor;
this.xrefTargetsDialog = null;
};
DocBookCrossRefXrefAction.prototype =
Object.create(sync.actions.AbstractAction.prototype);
DocBookCrossRefXrefAction.prototype.constructor = DocBookCrossRefXrefAction;
DocBookCrossRefXrefAction.prototype.getDisplayName = function () {
return 'Insert cross reference (xref)';
};
DocBookCrossRefXrefAction.prototype.actionPerformed = function (callback) {
// This callback might have to be called at a later point, so save it until then.
this.callback = callback || function () {};
var chooser = workspace.getUrlChooser();
var context = new sync.api.UrlChooser.Context(sync.api.UrlChooser.Type.EXTERNAL_REF);
chooser.chooseUrl(context, this.showXrefTargetChooser.bind(this),
sync.api.UrlChooser.Purpose.CHOOSE);
};
DocBookCrossRefXrefAction.prototype.showXrefTargetChooser = function (url) {
if (url) {
// Create a dialog to display all targets, so the user can select one to insert
// cross reference.
this.xrefTargetsDialog = this.createXrefTargetsDialog();
this.populateXrefTargetsDialog(url);
this.xrefTargetsDialog.onSelect(function (key, e) {
if (key === 'ok') {
e.preventDefault();
this.xrefTargetChosen();
} else {
this.callback();
}
}.bind(this));
this.xrefTargetsDialog.show();
} else {
this.callback();
}
};
DocBookCrossRefXrefAction.prototype.createXrefTargetsDialog = function () {
var dialog = workspace.createDialog();
dialog.setTitle('Choose cross reference');
dialog.setButtonConfiguration(sync.api.Dialog.ButtonConfiguration.OK_CANCEL);
dialog.setPreferredSize(700, 500);
dialog.setResizable(true);
return dialog;
};
DocBookCrossRefXrefAction.prototype.populateXrefTargetsDialog = function (url) {
this.editor.getActionsManager()
.invokeOperation('ro.sync.servlet.operation.FindXrefTargetsOperation', {url: url})
.then(function(str) { return JSON.parse(str);})
.then(this.xrefTargetsReceived.bind(this))
};
DocBookCrossRefXrefAction.prototype.xrefTargetsReceived = function (targets) {
var container = this.xrefTargetsDialog.getElement();
if (!targets || !targets.length) {
container.textContent = 'No cross reference targets found in the chosen file';
} else {
for (var i = 0; i < targets.length; i++) {
var radio = document.createElement('input');
radio.name = 'docbook-ref-table-radio';
radio.type = 'radio';
radio.dataset.id = targets[i].id;
var label = document.createElement('label');
label.style = 'display: block';
label.appendChild(radio);
label.appendChild(document.createTextNode(targets[i].nodeName + ' (#' +
targets[i].id + ') - ' + targets[i].content.substring(0, 50)));
container.appendChild(label);
}
}
};
DocBookCrossRefXrefAction.prototype.xrefTargetChosen = function() {
var targetRadio = this.xrefTargetsDialog.getElement().querySelector(
'input[name="docbook-ref-table-radio"]:checked');
if (targetRadio) {
this.editor.getActionsManager().invokeOperation('InsertFragmentOperation',
{fragment: '<xref linkend="' + targetRadio.dataset.id + '"/>'})
.then(this.xrefInserted.bind(this));
}
};
DocBookCrossRefXrefAction.prototype.xrefInserted = function () {
this.xrefTargetsDialog && this.xrefTargetsDialog.dispose();
this.callback();
};
DocBookCrossRefXrefAction.prototype.dispose = function() {
this.xrefTargetsDialog && this.xrefTargetsDialog.dispose();
};
goog.events.listen(workspace, sync.api.Workspace.EventType.EDITOR_LOADED, function(e) {
var editor = e.editor;
goog.events.listen(editor, sync.api.Editor.EventTypes.ACTIONS_LOADED, function(e) {
editor.getActionsManager().registerAction('insert.cross.reference.xref',
new DocBookCrossRefXrefAction(editor));
});
});
AuthorOperationWithResult
to collect xref targets from the file chosen by the user. You can find below the code of this Java operation:package ro.sync.servlet.operation;
import java.net.URL;
import java.util.ArrayList;
import javax.xml.parsers.DocumentBuilder;
import org.codehaus.jackson.map.ObjectMapper;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import ro.sync.basic.util.URLUtil;
import ro.sync.ecss.extensions.api.ArgumentsMap;
import ro.sync.ecss.extensions.api.AuthorOperationException;
import ro.sync.ecss.extensions.api.webapp.AuthorDocumentModel;
import ro.sync.ecss.extensions.api.webapp.AuthorOperationWithResult;
import ro.sync.ecss.extensions.api.webapp.WebappRestSafe;
import ro.sync.xml.parser.ParserCreator;
@WebappRestSafe
public class FindXrefTargetsOperation extends AuthorOperationWithResult {
@Override
public String doOperation(AuthorDocumentModel model, ArgumentsMap args)
throws AuthorOperationException {
String urlString = (String) args.getArgumentValue("url");
try {
URL url = URLUtil.addAuthenticationInfo(
model.getAuthorAccess().getEditorAccess().getEditorLocation(),
new URL(urlString));
InputSource is = new InputSource(url.toString());
DocumentBuilder docBuilder = ParserCreator.newSchemaAwareDocumentBuilder();
Document document = docBuilder.parse(is);
ArrayList<XrefTarget> xrefTargets = new ArrayList<>();
gatherXrefTargets(document, xrefTargets);
return new ObjectMapper().writeValueAsString(xrefTargets);
} catch (Exception e) {
throw new AuthorOperationException(e.getMessage(), e);
}
}
public static class XrefTarget {
public final String id;
public final String nodeName;
public final String content;
public XrefTarget(Element elem) {
this.id = getIDValue(elem);
this.nodeName = elem.getTagName();
this.content = elem.getTextContent();
}
}
private static void gatherXrefTargets(Node node, ArrayList<XrefTarget> xrefTargets) {
if (node.getNodeType() == Node.ELEMENT_NODE) {
Element elem = (Element) node;
if (getIDValue(elem) != null) {
xrefTargets.add(new XrefTarget(elem));
}
}
NodeList childNodes = node.getChildNodes();
for (int i = 0; i < childNodes.getLength(); i++) {
gatherXrefTargets(childNodes.item(i), xrefTargets);
}
}
public static String getIDValue(Element elem) {
NamedNodeMap attributes = elem.getAttributes();
for (int i = 0; i < attributes.getLength(); i++) {
Attr attribute = (Attr)attributes.item(i);
// There are some ID attributes defined as such in the schema file.
if (attribute.isId() || "xml:id".equals(attribute.getName()) ||
"id".equals(attribute.getName())) {
return attribute.getValue();
}
}
return null;
}
}
You need to compile this Java class and add it as a JAR file in the classpath of your framework. More details here .