Congree API for Structure Editor
What is the Structure Editor?
The Congree Authoring Client does not use the editor API explicitly. It uses the abstraction intermediary layer (internal Congree Client API). When it comes to the implementation of this abstraction layer, each editor uses its own version. Structure Editor is one of them. It hides all the difficulties and nuances that have to be considered when implementing the internal Congree Client API (see Fig.1). Thus, the Structure Editor is not a content editor and does not have its own UI view. But at the same time, the Congree Authoring Client interacts with the Structure Editor as a full-fledged editor.
Fig.1 Сomponents interaction scheme
As shown in Fig. 1, the XML Editor is a built-in UI control to be used by an application uses somehow. Congree does not interact directly with this control. The application itself interacts with this control and informs the Structure Editor about all changes.
When do you need to use the Structure Editor?
The Structure Editor is required if the ISV application uses an XML editor which does not have a Congree integration. The Structure Editor makes it possible to integrate Congree into the application directly.
The Structure Editor provides its own API. Using this API, the ISV application can, through the Structure Editor, check any content. Congree will assume that it is working with a real editor.
How to integrate the Structure Editor into an application?
In order to integrate the Structure Editor into the application, Congree API for ISV applications should be used. Please read this article carefully before proceeding.
The Structure Editor provides its own implementation of the ICongreeBootstrapper interface. The implementation ICongreeBootstrapper has a co-class CongreeBootstrapperComShim.
[ uuid(6D01C672-7B61-45D3-826A-43D072EEEEB5) ] coclass CongreeBootstrapperComShim { [default] interface ICongreeBootstrapperComShim; };
The ProgId for the co-class CongreeBootstrapperComShim is "Congree.Bootstrapper.ComShim"
After creating and initializing the Congree bootstrapper, application should create the control context (method CreateControlContext of ICongreeBootstrapper). This method accepts the VARIANT control argument. This argument is an instance of the Structure Editor.
How to create an instance of the Structure Editor?
IStructureEditor is an interface of the required editor. This interface should be implemented on ISV application side, then provided to Congree.
IStructureEditor
IStructureEditor provides a structure editor API which is designed to work with XML editors, which have an XML as content.
[ odl, uuid(680648DB-EE74-4464-8763-7A6A24982150), version(1.0), dual, oleautomation ] interface IStructureEditor : IDispatch { [id(0x00000001), propget] HRESULT DocumentNode([out, retval] INode** pRetVal); [id(0x00000002), propget] HRESULT Selection([out, retval] INodeRange** pRetVal); [id(0x00000002), propputref] HRESULT Selection([in] INodeRange* pRetVal); [id(0x00000003)] HRESULT ReplaceRange( [in] INodeRange* range, [in] BSTR xml, [out, retval] INodeRange** pRetVal); [id(0x00000004), propget] HRESULT NodeComparer([out, retval] INodeComparer** pRetVal); };
Properties:
DocumentNode
Returns root node of the XML document - instance of INode with type Document.
Selection
Get/Set selected range of the editable document.
NodeComparer
Returns implementation of INodeComparer or NULL in order to use default implementation in Congree.
Methods:
ReplaceRange
Method needed to replace content of the certain range.
Parameters:
- range - replacement range
- xml - new range content in XML format
- pRetVal - return value. Range of the inserted content
INode
Provides access to the XML DOM. More about XML DOM here: https://www.w3schools.com/xml/dom_intro.asp
[ odl, uuid(2151A843-32F2-42A7-A0A7-CA1A13AB0817), version(1.0), dual, oleautomation ] interface INode : IDispatch { [id(0x00000001), propget] HRESULT NodeType([out, retval] short* pRetVal); [id(0x00000002), propget] HRESULT Name([out, retval] BSTR* pRetVal); [id(0x00000003), propget] HRESULT NamespaceURI([out, retval] BSTR* pRetVal); [id(0x00000004), propget] HRESULT Prefix([out, retval] BSTR* pRetVal); [id(0x00000005), propget] HRESULT Value([out, retval] BSTR* pRetVal); [id(0x00000006), propget] HRESULT PreviousSibling([out, retval] INode** pRetVal); [id(0x00000007), propget] HRESULT NextSibling([out, retval] INode** pRetVal); [id(0x00000008), propget] HRESULT FirstChild([out, retval] INode** pRetVal); [id(0x00000009), propget] HRESULT LastChild([out, retval] INode** pRetVal); [id(0x0000000a), propget] HRESULT ParentNode([out, retval] INode** pRetVal); [id(0x0000000b), propget] HRESULT DocumentNode([out, retval] INode** pRetVal); [id(0x0000000c), propget] HRESULT Attributes([out, retval] IEnumerable** pRetVal); [id(0x0000000e)] HRESULT Equals( [in] INode* node, [out, retval] VARIANT_BOOL* pRetVal); };
Properties:
NodeType
Returns type of XML node. Possible values:
Name
Returns name of the node or attribute.
NamespaceURI
Returns namespace URI of the node if exists or null.
Prefix
Returns namespace prefix of the node if exists or null.
Value
Returns node value.
PreviousSibling
Returns previous (left) sibling of the node. Can be null.
NextSibling
Returns next (right) sibling of the node. Can be null.
FirstChild
Returns the first child node. Null if childred nodes not exist or not applicable.
LastChild
Returns the last child node. Null if childred nodes not exist or not applicable.
ParentNode
Returns parent node. Null for root node of the document.
DocumentNode
Returns document node (node type Document).
Attributes
Returns collection of attributes of the Element node. Collection should contain INode with type Attribute and implements interface IEnumerable. Definition of IEnumerable can be found in .Net Framework types library(mscorlib.tlb).
Methods:
Equals
Method checks equality of nodes. Return VARIANT_TRUE if nodes are the same, otherwise return VARIANT_FALSE.
INodeComparer
[ odl, uuid(67C69C37-77D2-48BE-9F67-B9A675B0092D), version(1.0), dual, oleautomation ] interface INodeComparer : IDispatch { [id(0x60020000)] HRESULT Compare( [in] INode* x, [in] INode* y, [out, retval] long* pRetVal); };
Methods:
Compare
Method for compare offset of two nodes. Return 1 if start offset of node x is greater than node y. Return 0 if node x has the same offset as node y. In all other cases return 1.
INodeRange
[ odl, uuid(DE0B1D9A-A500-4ADA-BDED-71905048C7CF), version(1.0), dual, oleautomation ] interface INodeRange : IDispatch { [id(0x00000001), propget] HRESULT BeginNode([out, retval] INode** pRetVal); [id(0x00000002), propget] HRESULT BeginOffset([out, retval] long* pRetVal); [id(0x00000003), propget] HRESULT EndNode([out, retval] INode** pRetVal); [id(0x00000004), propget] HRESULT EndOffset([out, retval] long* pRetVal); };
Properties:
BeginNode
Returns node where range begins.
BeginOffset
Returns offset of start of the range inside BeginNode.
EndNode
Returns node where range ends.
EndOffset
Returns offset of end of the range inside EndNode.
If BeginNode/EndNode is a TextNode or Whitespace or SignificantWhitespace, then offset equals offset inside text. For all other nodes the following values are possible:
0 - offset before node
1 - offset before node content
2 - offset after node content
3 - offset after node
Exception: Offset inside EntityReference can be 0 and 1 only
IStructureEditorEvents
In order to notify Congree about user interaction with the editor, instance of the Structure Editor should provide IStructureEditorEvents interface. Congree subscribes to the events and reacts on user actions.
[ uuid(504996B3-6EAB-43A8-8E62-9070741D3CB0), version(1.0) ] dispinterface IStructureEditorEvents { properties: methods: [id(0x00000001)] void OnDocumentChanged([in] INode* node); [id(0x00000002)] void OnSelectionChanged([in] INodeRange* range); };
Methods:
OnDocumentChanged
Notifies about changes in document node.
- Parameter: node - changed node
OnSelectionChanged
Notifies if selection in document was changed.
- Parameter: range - selected range
If user moves cursor inside editor, OnSelectionChanged should also be called. In this case, begin and end offsets of the range will be the same.