Simplest approach to an Author-mode customization
-
- Posts: 178
- Joined: Wed Apr 20, 2005 5:43 pm
- Location: Victoria, BC, Canada
Simplest approach to an Author-mode customization
Post by martindholmes »
I'd like to ask what the most effective approach will be to providing the following simple sequence of actions in Author mode, through a plugin. I'd like to use JavaScript rather than Java, but if Java is required, I can live with it.
This is the sequence of actions:
1. User selects text, which causes a toolbar button and context menu item to become enabled.
2. User clicks that item.
3. Check that text is selected.
4. Generate a unique @xml:id, and present it to the user to change or use as they see fit.
5. Insert an anchor at the selection start position with @next="#the_id".
5. Insert an anchor at the selection end position with @xml:id="the_id".
6. Add @ana to the first anchor, and place the cursor inside it.
7. Provide a drop-down list of values for that @ana, taken from a RelaxNG schema, with annotations also from the schema, just like when editing an attribute in the Text mode of Oxygen.
I can already do 4 through 6 using a Code Template in Text mode, and the schema then provides options for the attribute value, but this doesn't work in Author modes. I see that I can easily do 3 through 5 using JS to talk to the API:
https://www.oxygenxml.com/InstData/Edit ... rPage.html
But I can't see from the examples in the JavaScript examples on GitHub how to construct a dialog box from schema values, including the explanatory annotations, such as we see in Text mode. Can someone point me at some examples?
Re: Simplest approach to an Author-mode customization
To get you started on this, here's a sample Oxygen plugin (Javascript based) which adds a contextual menu to the Author visual editing mode:
https://github.com/oxygenxml/wsaccess-j ... AuthorPage
now going back to your questions:
Let's focus first on the contextual menu action, you can choose to add it or not to the contextual menu depending on what the "authorAccess.getEditorAccess().hasSelection()" method returns.1. User selects text, which causes a toolbar button and context menu item to become enabled.
Again, use authorAccess.getEditorAccess().hasSelection(). Maybe also use authorAccess.getEditorAccess().getSelectedText() because in the Author mode the end user may select element tags without selecting any relevant text.2. User clicks that item.
3. Check that text is selected.
Maybe use something like:4. Generate a unique @xml:id, and present it to the user to change or use as they see fit.
Code: Select all
Packages.ro.sync.exml.workspace.api.PluginWorkspaceProvider.getPluginWorkspace().getUtilAccess().expandEditorVariables("${id}", null)
Then present it to the end user using something like:
Code: Select all
var selectedValue = Packages.javax.swing.JOptionPane.showInputDialog(
pluginWorkspaceAccess.getParentFrame(),"Please set the ID value", defaultIDValue);
Probably something like:5. Insert an anchor at the selection start position with @next="#the_id".
ro.sync.ecss.extensions.api.AuthorDocumentController.insertXMLFragment(String, int)
Code: Select all
documentController.insertXMLFragment("<anchor id='" + uniqueID + "'/>",
authorAccess.getEditorAccess().getSelectionStart());
Same but instead use the "getSelectionEnd()" API.5. Insert an anchor at the selection end position with @xml:id="the_id".
Either add the attribute directly when the "insertXMLFragment" is called with the anchor.6. Add @ana to the first anchor, and place the cursor inside it.
Or use our API to set an attribute on a certain element:
https://github.com/oxygenxml/javascript ... lements.js
We have a sample plugin which shows a dialog with a list of values here:7. Provide a drop-down list of values for that @ana, taken from a RelaxNG schema, with annotations also from the schema, just like when editing an attribute in the Text mode of Oxygen.
I can already do 4 through 6 using a Code Template in Text mode, and the schema then provides options for the attribute value, but this doesn't work in Author modes. I see that I can easily do 3 through 5 using JS to talk to the API:
....
But I can't see from the examples in the JavaScript examples on GitHub how to construct a dialog box from schema values, including the explanatory annotations, such as we see in Text mode. Can someone point me at some examples?
https://github.com/oxygenxml/wsaccess-j ... Completion
but you would like those values to come from the schema associated to the XML document.
So you would probably also need to use these APIs:
https://www.oxygenxml.com/InstData/Edit ... aManager--
Code: Select all
ro.sync.ecss.extensions.api.AuthorSchemaManager.createWhatPossibleValuesHasAttributeContext(AuthorElement, String)
Code: Select all
ro.sync.ecss.extensions.api.AuthorSchemaManager.whatPossibleValuesHasAttribute(WhatPossibleValuesHasAttributeContext)
Radu
<oXygen/> XML Editor
http://www.oxygenxml.com
-
- Posts: 178
- Joined: Wed Apr 20, 2005 5:43 pm
- Location: Victoria, BC, Canada
Re: Simplest approach to an Author-mode customization
Post by martindholmes »
-
- Posts: 178
- Joined: Wed Apr 20, 2005 5:43 pm
- Location: Victoria, BC, Canada
Re: Simplest approach to an Author-mode customization
Post by martindholmes »
This is working nicely so far, but I'm having a problem getting my plugin's right-click menu item to show up when the project itself has a document type defined, with its own Author Mode CSS. Is there something special I have to do in the Document Type configuration to make my plugin available? It works fine as long as I'm editing a document in a project with no configured document types, but I really need to be able to do this for a configured document type.
All help appreciated,
Martin
Re: Simplest approach to an Author-mode customization
A plugin should work alongside any opened XML document, no matter to what document type configuration it pertains.
If you start Oxygen using its "oxygen.bat" command line executable (from the Oxygen installation folder) does it report any error?
Can you show me some source code with your current approach? If the plugin is not open source maybe you can send it to support@oxygenxml.com
Regards,
Radu
<oXygen/> XML Editor
http://www.oxygenxml.com
-
- Posts: 178
- Joined: Wed Apr 20, 2005 5:43 pm
- Location: Victoria, BC, Canada
Re: Simplest approach to an Author-mode customization
Post by martindholmes »
I'm running Oxygen on Ubuntu 18.10 using the default startup script:
/home/mholmes/Oxygen XML Editor 21/oxygen21.0
This is my plugin.xml:
Code: Select all
<!DOCTYPE plugin PUBLIC "-//Oxygen Plugin" "../plugin.dtd">
<plugin
id="com.oxygenxml.popup.endingsAna"
name="Add Analysis Tagging To Author page popup-menu"
description="Plugin adds contextual menu action to Author page pop-up menu allowing tagging of a fragment with a specific analytic category."
version="1.0"
vendor="HCMC"
class="ro.sync.exml.plugin.Plugin"
classLoaderType="preferReferencedResources">
<extension type="WorkspaceAccessJS" href="wsAccess.js"/>
</plugin>
Code: Select all
/* Adapted from example for working with the Author editing mode, started from: https://www.oxygenxml.com/forum/post49889.html#p49886 */
function applicationStarted(pluginWorkspaceAccess) {
Packages.java.lang.System.err.println("Application started " + pluginWorkspaceAccess);
var edChangedListener = {
/*Called when a document is opened*/
/*See: https://www.oxygenxml.com/InstData/Editor/SDK/javadoc/ro/sync/exml/plugin/workspace/WorkspaceAccessPluginExtension.html */
editorOpened: function(editorLocation) {
Packages.java.lang.System.err.println("\nrunning " + editorLocation);
/*Get the opened editor, each opened XML document corresponds to "WSEditor" object*/
/* See: https://www.oxygenxml.com/InstData/Editor/SDK/javadoc/ro/sync/exml/workspace/api/PluginWorkspace.html#getEditorAccess-java.net.URL-int- */
var editor = pluginWorkspaceAccess.getEditorAccess(editorLocation, Packages.ro.sync.exml.workspace.api.PluginWorkspace.MAIN_EDITING_AREA);
/* An editor (WSEditor) has three editing modes (Text/Grid/Author) so we need to check that it's opened in the "Author" editing mode */
/* We can also add listeners to know when end user switches between edit modes */
/* WSEditor API: https://www.oxygenxml.com/InstData/Editor/SDK/javadoc/ro/sync/exml/workspace/api/editor/WSEditor.html */
if (editor.getCurrentPageID() == "Author") {
//The current editor is opened in the "Author" visual editing mode
authorPage = editor.getCurrentPage();
/*Add listener called when right click is performed in the Author editing mode*/
/* See: https://www.oxygenxml.com/InstData/Editor/SDK/javadoc/ro/sync/exml/workspace/api/editor/page/author/WSAuthorEditorPageBase.html */
customizerObj = {
customizePopUpMenu: function(popUp, authorAccess) {
Packages.java.lang.System.err.println("RIGHT CLICK" + popUp);
try {
/*Create menu items, the Javascript plugin creates Swing components (menu items in this case)
* because Oxygen is Java Swing based. */
mi = new Packages.javax.swing.JMenuItem("Tag analysis");
popUp.add(mi);
actionPerfObj = {
actionPerformed: function(e) {
var selText = authorAccess.getEditorAccess().getSelectedText();
Packages.java.lang.System.err.println("Selection length: " + selText.length());
try {
/* Check if have selected content */
if (selText.length() > 0) {
var uid = Packages.ro.sync.exml.workspace.api.PluginWorkspaceProvider.getPluginWorkspace().getUtilAccess().expandEditorVariables("${id}", null);
Packages.java.lang.System.err.println("Generated id: " + uid);
documentController = authorAccess.getDocumentController();
var selEnd = authorAccess.getEditorAccess().getSelectionEnd();
var selStart = authorAccess.getEditorAccess().getSelectionStart();
Packages.java.lang.System.err.println("selStart: " + selStart + "; selEnd: " + selEnd);
//We have to add the anchor at selEnd first, otherwise the offsets get screwed and the
//second anchor is inserted in the wrong place.
documentController.insertXMLFragment("<anchor xml:id='" + uid + "'/>", selEnd);
documentController.insertXMLFragment("<anchor next='#" + uid + "'/>", selStart);
//Now we need to add the attribute value. First find the element we just added.
var newEl = documentController.findNodesByXPath("//anchor[@xml:id = '" + uid + "']", true, true, true);
documentController.setAttribute("ana", new Packages.ro.sync.ecss.extensions.api.node.AttrValue("testing"), newEl[0]);
}
} catch (e1) {
e1.printStackTrace();
}
}
}
mi.addActionListener(new JavaAdapter(Packages.java.awt.event.ActionListener, actionPerfObj));
} catch (e1) {
Packages.java.lang.System.err.println(e1);
}
}
}
//Add the popup menu customizer.
authorPage.addPopUpMenuCustomizer(new Packages.ro.sync.ecss.extensions.api.structure.AuthorPopupMenuCustomizer(customizerObj));
}
}
}
var edChangedListenerAdapter = new JavaAdapter(Packages.ro.sync.exml.workspace.api.listeners.WSEditorChangeListener, edChangedListener);
/* Add the editor changed listener */
pluginWorkspaceAccess.addEditorChangeListener(
edChangedListenerAdapter,
Packages.ro.sync.exml.workspace.api.PluginWorkspace.MAIN_EDITING_AREA);
}
function applicationClosing(pluginWorkspaceAccess) {
/* The application is closing */
Packages.java.lang.System.err.println("Application closing " + pluginWorkspaceAccess);
}
Code: Select all
Exception in thread "AWT-EventQueue-0" org.mozilla.javascript.EcmaError: TypeError: Cannot find function printStackTrace in object InternalError: Can't find method ro.sync.ecss.g.i.setAttribute(string,ro.sync.ecss.extensions.api.node.AttrValue,org.mozilla.javascript.Undefined). (file:/home/mholmes/Oxygen%20XML%20Editor%2021/plugins/endingsPluginAna/wsAccess.js#49). (file:/home/mholmes/Oxygen%20XML%20Editor%2021/plugins/endingsPluginAna/wsAccess.js#53)
One last question: how do I specify a namespace for elements I insert? They're being inserted in the empty namespace right now.
-
- Posts: 178
- Joined: Wed Apr 20, 2005 5:43 pm
- Location: Victoria, BC, Canada
Re: Simplest approach to an Author-mode customization
Post by martindholmes »
At the moment, the operation (which inserts two elements and adds an attribute) is carried out in three steps; that means that if the user wants to undo it, they need to undo three times, which is a little confusing for them. Is there a way to wrap a sequence of actions in the plugin such that they become a single undo step?
Thanks,
Martin
-
- Posts: 178
- Joined: Wed Apr 20, 2005 5:43 pm
- Location: Victoria, BC, Canada
Re: Simplest approach to an Author-mode customization
Post by martindholmes »
If a document is opened in Author mode, then it gets the item. If it's opened in Text mode (which is the default for most of our projects), then it doesn't get the item, even when it's switched to Author mode, because the edChangedListener is listening for document open events only.
So I need to add an event listener for when the edit mode is changed, in addition to when a document is opened or selected. I can't see a way to do that.
Cheers,
Martin
Re: Simplest approach to an Author-mode customization
So:
That's the problem with this particular popup menu customizer API you are using, indeed you would need to add an extra listener on the opened WSEditor, and we have this listener:If a document is opened in Author mode, then it gets the item. If it's opened in Text mode (which is the default for most of our projects), then it doesn't get the item, even when it's switched to Author mode, because the edChangedListener is listening for document open events only.
So I need to add an event listener for when the edit mode is changed, in addition to when a document is opened or selected. I can't see a way to do that.
https://www.oxygenxml.com/InstData/Edit ... dListener-
so this can be done but the code becomes more complicated. This is why in Oxygen 18 we added this new API:
https://www.oxygenxml.com/InstData/Edit ... ustomizer-
and each time the popup menu is shown in the Author visual editing mode the customizer issues a specific callback that you can implement on your side:
https://www.oxygenxml.com/InstData/Edi ... horAccess-
I do not seem to have a sample about how to do this from Javascript, if you have difficulties with it I can try to come up with some sample code.
The new "MenusAndToolbarsContributorCustomizer" API also has callbacks for populating the main Author menu and also the Author toolbar (which might also come handy).
Right, use:At the moment, the operation (which inserts two elements and adds an attribute) is carried out in three steps; that means that if the user wants to undo it, they need to undo three times, which is a little confusing for them. Is there a way to wrap a sequence of actions in the plugin such that they become a single undo step?
Code: Select all
documentController.beginCompoundEdit();
////DO STUFF HERE
documentController.endCompoundEdit();
Specify the namespace directly in the XML like:One last question: how do I specify a namespace for elements I insert? They're being inserted in the empty namespace right now.
Code: Select all
documentController.insertXMLFragment("<anchor xml:id='" + uid + "' xmlns=\"http://www.tei-c.org/ns/1.0\"/>", selEnd);
Regards,
Radu
<oXygen/> XML Editor
http://www.oxygenxml.com
-
- Posts: 178
- Joined: Wed Apr 20, 2005 5:43 pm
- Location: Victoria, BC, Canada
Re: Simplest approach to an Author-mode customization
Post by martindholmes »
All the best,
Martin
Re: Simplest approach to an Author-mode customization
Well, I originally created this Javascript-based plugin extension in order to get more people to start creating plugins for Oxygen. As the code grows in complexity I think you need to start to consider moving to Java because it provides compilation time errors, better IDEs (Eclipse, IntelliJ) and the code looks cleaner in Java.
The easiest start to create a Java-based Workspace Access plugin is by cloning this Maven-based project in the Eclipse workspace (Eclipse being an open source IDE for editing Java and other languages):
https://github.com/oxygenxml/sample-plu ... ace-access
Regards,
Radu
<oXygen/> XML Editor
http://www.oxygenxml.com
-
- Posts: 178
- Joined: Wed Apr 20, 2005 5:43 pm
- Location: Victoria, BC, Canada
Re: Simplest approach to an Author-mode customization
Post by martindholmes »
Meanwhile, I'll download the SDK and start getting comfortable with the Java.
Cheers,
Martin
Re: Simplest approach to an Author-mode customization
I re-wrote the Author contextual popup menu example to use the new API, this greatly simplifies the code, you no longer need to add an editor opened listener:
https://github.com/oxygenxml/wsaccess-j ... sAccess.js
and I did the same thing for the Text page popup menu customizer:
https://github.com/oxygenxml/wsaccess-j ... sAccess.js
Regards,
Radu
<oXygen/> XML Editor
http://www.oxygenxml.com
-
- Posts: 178
- Joined: Wed Apr 20, 2005 5:43 pm
- Location: Victoria, BC, Canada
Re: Simplest approach to an Author-mode customization
Post by martindholmes »
Return to “SDK-API, Frameworks - Document Types”
- Oxygen XML Editor/Author/Developer
- ↳ Feature Request
- ↳ Common Problems
- ↳ DITA (Editing and Publishing DITA Content)
- ↳ SDK-API, Frameworks - Document Types
- ↳ DocBook
- ↳ TEI
- ↳ XHTML
- ↳ Other Issues
- Oxygen XML Web Author
- ↳ Feature Request
- ↳ Common Problems
- Oxygen Content Fusion
- ↳ Feature Request
- ↳ Common Problems
- Oxygen JSON Editor
- ↳ Feature Request
- ↳ Common Problems
- Oxygen PDF Chemistry
- ↳ Feature Request
- ↳ Common Problems
- Oxygen Feedback
- ↳ Feature Request
- ↳ Common Problems
- Oxygen XML WebHelp
- ↳ Feature Request
- ↳ Common Problems
- XML
- ↳ General XML Questions
- ↳ XSLT and FOP
- ↳ XML Schemas
- ↳ XQuery
- NVDL
- ↳ General NVDL Issues
- ↳ oNVDL Related Issues
- XML Services Market
- ↳ Offer a Service