Could not determine conref targets

Oxygen general issues.
boopathyks
Posts: 4
Joined: Thu Oct 24, 2019 2:43 pm

Could not determine conref targets

Post by boopathyks »

I have created the new XRef menu in the Oxygen Web Author by using the below code on the web/framework.js

Code: Select all

var insertXrefActionId =
    sync.docbook.DocbookExtension.prototype.version == 5 ? "insert.cross.reference.xref" : "insert.cross.reference.link";

console.log(sync.docbook.DocbookExtension.prototype.version);
var originalInsertXrefAction = actionsManager.getActionById(insertXrefActionId);
console.log(originalInsertXrefAction);
if (originalInsertXrefAction) {
    var xrefOperationClass = sync.docbook.DocbookExtension.prototype.version == 5 ?
        "ro.sync.ecss.extensions.docbook.link.InsertXrefOperation" :
        "ro.sync.ecss.extensions.commons.operations.SurroundWithFragmentOperation";
    console.log(xrefOperationClass);
    var insertXrefAction = new sync.actions.InsertXref(
        originalInsertXrefAction,
        editor
    );
    console.log(insertXrefAction);
    actionsManager.registerAction(insertXrefActionId, insertXrefAction);
}
The Menu is working well, But when I select the Xml file for cross Reference. I'm getting the below error

Could not determine conref targets

Console.log:

TypeError: Cannot read property 'focus' of null
at sync.actions.InsertXref.sync.actions.InsertReference.focusElemChooser


Kindly help me to find the solution.
cristi_talau
Posts: 495
Joined: Thu Sep 04, 2014 4:22 pm

Re: Could not determine conref targets

Post by cristi_talau »

Hello,

The "sync.actions.InsertXref" action was designed to work for DITA documents. I registered an issue to make add similar functionality for DocBook and I will update this thread when it will be available in a released version of Web Author.

Let us know if you want to test beta version of the DocBook framework that includes this functionality, please write us an email on support@oxygenxml.com .

Meanwhile, you can implement your own action in your DocBook framework extension. To do this you need to:

1. Create a custom action that prompts the user to choose the destination file and the ID of the target element. The code for this action needs to be added in the "web" folder of you framework in a new JS file. You can find below a minimal working example:

Code: Select all

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));
  });
});
2. This action uses a server-side AuthorOperationWithResult to collect xref targets from the chosen file. You can find below the code of this Java operation:

Code: Select all

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:https://www.oxygenxml.com/doc/versions/ ... h-tab.html .

Best,
Cristian
mixa999999
Posts: 1
Joined: Thu Mar 19, 2020 2:29 pm

Re: Could not determine conref targets

Post by mixa999999 »

cristi_talau wrote: Fri Oct 25, 2019 3:39 pm ...
You need to compile this Java class and add it as a JAR file in the classpath of your framework.
Best,
Cristian
is there any way to make this work in author standalone, not on the web?
cristi_talau
Posts: 495
Joined: Thu Sep 04, 2014 4:22 pm

Re: Could not determine conref targets

Post by cristi_talau »

Hello,

This thread is about adding actions to insert cross references to the Docbook framework in Web Author. Currently, these actions are supported out-of-the-box in both Web Author and standalone Author.

In this context, it would be helpful to give us more details about what you are trying to achieve.

To implement an "Insert Reference" action for some other XML vocabulary, you may find these tutorials useful: Best regards,
Cristian
Post Reply