功能不适用于新创建的菜单
functionality is not working for newly created menu
我正在 Oxygen Web-Author 上创建 Link 菜单,已经有两个名为 "ulink" 和 "uri" 的菜单。当我包含名为外部参照的第三个菜单时,外部参照的功能无法正常工作,它在氧气 framework.js.
中使用 "ulink" 功能
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);
}
这里已经用上面的代码插入了菜单,其中insert.web.link和insert.web.ulink代表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>
所以我想插入外部参照菜单到javascript,外部参照菜单和class路径代表insert.cross.reference.xref和
ro.sync.ecss.extensions.docbook.link.InsertXrefOperation对应。
您可以在 DocBook 框架扩展中实现您自己的 "Insert Cross Reference (xref)" 操作版本。为此,您需要:
- 创建一个自定义操作,提示用户选择目标文件和目标元素的 ID。此操作的代码需要添加到框架的 "web" 文件夹中的新 JS 文件中。您可以在下面找到一个最小的工作示例:
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
从用户选择的文件中收集外部参照目标。您可以在下面找到此 Java 操作的代码:
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;
}
}
您需要编译此 Java class 并将其作为 JAR 文件添加到框架的 class 路径中。更多详情 here .
我正在 Oxygen Web-Author 上创建 Link 菜单,已经有两个名为 "ulink" 和 "uri" 的菜单。当我包含名为外部参照的第三个菜单时,外部参照的功能无法正常工作,它在氧气 framework.js.
中使用 "ulink" 功能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);
}
这里已经用上面的代码插入了菜单,其中insert.web.link和insert.web.ulink代表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>
所以我想插入外部参照菜单到javascript,外部参照菜单和class路径代表insert.cross.reference.xref和 ro.sync.ecss.extensions.docbook.link.InsertXrefOperation对应。
您可以在 DocBook 框架扩展中实现您自己的 "Insert Cross Reference (xref)" 操作版本。为此,您需要:
- 创建一个自定义操作,提示用户选择目标文件和目标元素的 ID。此操作的代码需要添加到框架的 "web" 文件夹中的新 JS 文件中。您可以在下面找到一个最小的工作示例:
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
从用户选择的文件中收集外部参照目标。您可以在下面找到此 Java 操作的代码:
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;
}
}
您需要编译此 Java class 并将其作为 JAR 文件添加到框架的 class 路径中。更多详情 here .