Home Forums General XMetaL Discussion Styling custom PI’s Reply To: Styling custom PI’s

Derek Read

Reply to: Styling custom PI’s

I don't think you can do what you want to do using just CSS. Also, the Change Tracking PIs XMetaL supports are not really connected to CSS (you can't style every aspect of them like you can with other things) so there is no hope of hooking into that somehow.

The closest to what you are asking for might be to try to use CSS:before or CSS:after pseudo-selectors, plus some generated content (using the CSS property “content”) — I suspect that is what you might be hoping for (ie: some magic CSS settings). Something like the following:

$procins[xm-pi-target="mytarget"]:before {
color: red;
content: "test";

However, that isn't going to let you grab the DATA portion of the PI, nor will it allow you to suppress just the TARGET.

What I think you might try is a script like the following that uses the SetRenderedContent API. This API has not been extensively tested for PI nodes (typical usage is to replace PCDATA). So, please test thoroughly before rolling out any solution based on this idea.

This will not give you identical behavior to the Change Tracking PIs, but I think it might be as close as you can get. The most notable difference is that you cannot select content rendered this way merely by clicking on it, as you can with the Change Tracking PIs and there is no way to make the opening and closing PI tags go away using this technique.

1. Create a macro containing code below.
2. Open any document containing your own custom PI.
3. Place your cursor (insertion point) anywhere inside the PI.
4. Run the macro.

[code]//XMetaL Script Language JSCRIPT:
Create a Range object to work with the user's current selection,
which is assumed to be inside a PI
In your final version of this script you would probably skip this step
and obtain a list of your PIs as nodes using other APIs, DOM, etc…
var rng = ActiveDocument.Range;

//Change the selection to grab the entire PI…

//Store the current node, which should equal the PI…
var curNode = rng.ContainerNode;

//Only continue if we're inside a PI, otherwise display an error…
if (curNode.NodeType == 7) {
//Store the text for the PI…
var piAll = rng.Text;

//Display current value of our string…
Application.Alert(“Here's the entire PI, Target + Data:r” + piAll);

//Store just the DATA portion from our string
if (piAll.indexOf(” “) == -1) {
/*oops, didn't find a space,
so there cannot be a Data portion,
insert something anyway…
var piData = “— NO PI DATA —“;
else {
//DATA in a PI is everything after the first space…
var piData = piAll.substr(piAll.indexOf(” “) + 1);
//Display the altered string, this equals the DATA portion…
Application.Alert(“Here's just the Data from the PI:r” + piData);

//Replace the text being rendered for the PI's node with the new string…
else {
//User wasn't inside a PI, display error…
Application.Alert(“To run this demo first put your cursor inside a PI.”);

You will need to create a number of scripts that walk your document to find your PIs and render new content for them during various events in order to make sure the rendered content is always replaced with what you want it to be. Most likely a document open event, an event for view switching (this rendered content will be lost when you move to PlainText view and back to TagsOn / Normal) and probably insertion of new PIs, possibly also including pasting.