Pages: 1
Print
Author Topic: How to Disallow Empty Elements?  (Read 642 times)
Marvin
Member

Posts: 22


« on: April 23, 2018, 10:13:25 AM »

We curently use XMetal Author 9 (yes, we're working on upgrading to a newer version) and have some "XRef" elements we don't want to allow to be empty.

From what I've read, DTDs don't support that restriction (only XSD schemas do).
Also, it would be nice if users could get immediate feedback when they move the selection away from the XRef element, and not only when they save the document, which could possibly be much later.

I have tried to use the On_Update_ElementList event for this, but I can't seem to figure out where to go from there:
It seems like you can't even open message boxes, so I struggled to even see what was happening (or if my macro was called at all).

Any help would be highly appreciated.
Logged
Derek Read
Program Manager (XMetaL)
Administrator
Member

Posts: 2579



WWW
« Reply #1 on: April 23, 2018, 02:22:40 PM »

The event On_Update_ElementList (and associated APIs) allow you to change or restrict what is displayed in the Element List, so I don't think that's what you want.

You want to add additional validation requirements that cannot be defined in the DTD. We tend to refer to these as "business rules" (though I don't know if that term is actually used anywhere officially). However, it sounds like you also want to guide the user so they are unlikely to see a validation error. Both of these are doable.

The simplest method to guide a user to enter text is to use the <?xm_replace-text?> PI. The difference between this an a normal PI is the way it is displayed and the fact that the entire PI is selected when click on, allowing the user to type over it.

You can use these PIs inside a document template (the files in the Template subfolder) or inside the "mini template" for a particular element.

The mini template can be used to create a chunk of XML to insert when the user inserts an element from the Element List. This is defined for each element in the CTM file. Whatever is in the mini template is inserted instead of just the element. If there is content that must always be inserted for a particular element you can include that in the mini template for the element as well, including text, child elements and their children and/or text, and/or attributes and their values.

Another method might be to pop up a dialog when the user inserts the <XRef> element and then have that dialog guide the user into creating something acceptable, perhaps by simply asking them to fill in a text form and checking to see that they entered something or that they entered something that matches a particular format. However, as an <XRef> implies a URL or path of some kind you might also display a "browse to file" dialog and use the path they pick, or maybe ask the user to copy the address from web browser to the clipboard and then read that into the dialog, something else?

XMetaL Author supports its own form format: XFT. You create these in the XMetaL Forms Layout tool included with XMetaL Developer. Then you hook up the form to either display as a popup or embed it inline in the document (for a particular element) by setting the appropriate settings in the CTM file associated with the DTD.

You can also pop up a dialog inside the On_Click or On_Double_Click events (fired when the user clicks in the document) using the CreateFormDlg() method.

The Journalist customization has a number of form examples (as does the DITA author functionality, though these are typically written in much more complex fashion so that a single XFT morphs how it looks in order to allow it to be reused for multiple elements and situations). The following Journalist elements either trigger the display of an XFT form or show an embedded XFT form when the element is inserted:
<Author>
<PubDate>
<ULink>
<Annotation>

Yet another approach (one that you might want to include even if one of those above is also implemented) would be to use the event On_Check_Element_SimpleContent. This runs whenever the document is validated (ie: if the user requests it via F9 or during save or open). In here you can check the PCDATA content for an element and create a corresponding custom error message if your requirements are not met. This means the user needs to insert an <XRef> put in the wrong content (or in your case no content) then they are told about it when they validate or save (just like any other validation issues). This way, if the user somehow gets past your guide and manages to create something that violates your rule (Plain Text editing is the easiest, or perhaps in another piece of software) this code would still catch the issue.

The On_Check_Attribute_Value is a similar event that that lets you check attribute values according to your own business rules.

The XMetaL Developer Customization Guide has information on all of these things.

Keep in mind that XMetaL Author has a feature called Rules Checking that other products don't have. Most products only validate documents (at various times) showing you what is wrong with them after the issue has been introduced. The rules checking feature in XMetaL Author attempts to stop someone from creating an invalid document in the first place. It does this through various means: by listing only valid elements in the Element List (for the current position in the document), by stopping people from pasting in invalid elements, by stopping you from dragging and dropping content to places where it will be invalid, by stopping you from deleting elements (which is not always possible), by stopping you from setting bad attribute values, etc. This feature works automatically based on the definitions in the DTD or XSD, which also means the only way to get it to function is to make modifications to the DTD or XSD.
« Last Edit: April 23, 2018, 02:29:46 PM by Derek Read » Logged
Marvin
Member

Posts: 22


« Reply #2 on: April 24, 2018, 08:25:42 AM »

Thank you for the detailed reply (btw, we also have a support agreement, but I figured someone else might find this useful, so I decided to just ask her instead).

We're already using the <?xm-replace-text?> PI, like so:

Code:
<xref href="#to-be-resolved" id="xref_F767C1E1..."><?xm-replace_text Cross reference?></xref>

I'm not sure how it's implemented, but doubleclicking on that actually opens a dialog that lets you select something.
But we have issues with some users editing the xref contents (label), believing they could change the target, or deleting the label alltogether (thus creating an empty element, which causes problems for us elsewhere).

To make sure they don't change existing xref elements, this works like a charm:

Code:
<MACRO name="On_Application_Document_Open_Complete" lang="JScript" hide="true"><![CDATA[
var elemName = "xref";
var rng = ActiveDocument.Range;
rng.MoveToDocumentStart();
while(rng.MoveToElement(elemName)) {
rng.ReadOnlyContainer = true;
}
]]></MACRO>

As for the "business rule validation," I have found this great example and have adapted the code to our needs, more or less.
Here is the relevant code:

Code:
<MACRO name="On_Check_Element_SimpleContent" key="" lang="JScript" hide="true"><![CDATA[
var cd = Application.CheckData;
var elem = cd.Element;
var name = elem.tagName;
 
if(name == "xref") {
var value = cd.Value;
if(value == null || value == "") {
cd.ValidationMsg = "Empty xrefs are not allowed. If the xref is marked as read-only, please delete it and create a new one.";
}
}
]]></MACRO>

But unfortunately value is always "" (empty string).
Can this be related to the <?xm-replace_text?> PI? Maybe the macro doesn't even see the contents?

The code is quite difficult to debug as I basically have to resort to message boxes and the likes. If I could step through it line by line and inspect variables, it would be much easier. I guess there's no way to achieve that?
I also couldn't even extract the properties from the variables at runtime (JSON.stringify(elem) etc.).

And like I said, we're currently using XMetaL Author 9, but we're working on upgrading to version 13. Are there any new features that would make handling this easier?

Thank you.
« Last Edit: April 24, 2018, 08:29:22 AM by Marvin » Logged
Derek Read
Program Manager (XMetaL)
Administrator
Member

Posts: 2579



WWW
« Reply #3 on: April 24, 2018, 02:20:50 PM »

Sounds like your customization is quite extensive already.

It is possible that checking for an empty value in that event might fail. I'm not aware of that limitation but it is possible.

I can't think of any *new* features in 13 that would help in this specific case. There might be other features you could take advantage of though. There are many other events and there are over 1000 APIs.

Perhaps you might try implementing something in On_Before_Document_Validate. You could walk the document in there (similar to the logic in your On_Document_Open_Complete macro) and look for issues, then display messages to the user. I could imagine a UI that takes the user directly to an <xref> that has issues and shows them your existing xref dialog, but perhaps with a "please fix this" message. The same XFT could probably be duplicated and modified so it contains slightly different prompts.

If you have Visual Studio or the Windows Script Debugger installed you can launch a debugging session by adding the keyword "debugger" into your script. This will allow you to step through your code and use the features that debugger provides.

If you have XMetaL Developer this is quite a bit simpler as you can launch XMetaL Author Enterprise from within Visual Studio in this case in debug mode, put breakpoints in your scripts, and gain all the advantages of Visual Studio's debugging system that way (including in some cases step over, step out, etc). The Programmers Guide and Customization Guide are written assuming you have XMetaL Developer (they ship with that software) but you can download CHM copies from our website if you don't have or don't want to use XMetaL Developer.
Logged
Marvin
Member

Posts: 22


« Reply #4 on: April 30, 2018, 04:46:39 PM »

Thanks, this was very valuable advice.

XMetaL Developer broke our connector, so that wasn't really an option. Using "debugger;" I can finally step through scripts, even if it's a bit annoying that I have to restart XMetaL Author every time I change something.

I could also solve the problem with <?xm-replace_text?> by simply removing it from the xref mini-template.

Thank you again!
Logged
Derek Read
Program Manager (XMetaL)
Administrator
Member

Posts: 2579



WWW
« Reply #5 on: May 01, 2018, 02:59:00 PM »

If you aren't using XMetaL Developer you can still use Ctrl+Alt+R to reload macros.

This only helps for macros in events that can still run (ie: some events only fire at startup).
Logged
Marvin
Member

Posts: 22


« Reply #6 on: May 01, 2018, 03:00:09 PM »

Thanks!
Logged
Pages: 1
Print
Jump to: