XMetaL Tips and Tricks

XMetaL Community Forum XMetaL Tips and Tricks Script Example: select a table row

  • Derek Read

    Script Example: select a table row

    Participants 1
    Replies 0
    Last Activity 12 years, 3 months ago

    Products: XMetaL Author (Enterprise and Essential) and XMAX
    Tested with XMetaL Author Enterprise 6.0.0.122

    The Question:
    Is it possible to select a table row using script?

    Yes, it is possible, but how useful it is once you get the selection will depend on your needs. It is also not easy to do given the current APIs we have for interacting with Range and Selection in the context of tables (which is why I'm sharing this code).

    Legal:
    * Licensed Materials – Property of JustSystems, Canada, Inc.
    *
    * (c) Copyright JustSystems Canada, Inc. 2010
    * All rights reserved.
    *
    *——————————————————————-
    * The sample contained herein is provided to you “AS IS”.
    *
    * It is furnished by JustSystems Corporation as a simple example and has not been
    * thoroughly tested under all conditions. JustSystems Canada, Inc., therefore, cannot
    * guarantee its reliability, serviceability or functionality.
    *
    * This sample may include the names of individuals, companies, brands and products
    * in order to illustrate concepts as completely as possible. All of these names are
    * fictitious and any similarity to the names and addresses used by actual persons or
    * business enterprises is entirely coincidental.
    *———————————————————————

    Background:
    The background behind why this is tricky is partly because Range and Selection in the context of CALS and HTML tables function differently from other elements (and partly because we have not implemented any APIs specific to this cause). It gets complicated because we allow people to select multiple cells in a table inside the same row but we also allow the selection to span rows (ie: two or more cells in one or more “columns”). There is no true concept of a “column” in these table types. By this I mean that cells are defined as children of rows, and rows are (ultimately) child elements in the table (yes, there is colspec in CALS tables but the XML source for the cells are not contained inside it).

    This means that although we allow users to (quite usefully) make such selections (for cut, copy, paste and delete) when they do so there are actually two things going on for tables that don't apply for any other element types: the underlying selection (the XML source) compared to the selection the user sees rendered in the table may be different. When the user selects one or more cells in one or mores “columns” the underlying XML source “selection” would not be contiguous so we need special functionality to deal with that case.

    For simplicity XMetaL basically always treats the two types of selections (the visible and the underlying representation of it) differently even when they could actually be the same (as in the case of selecting all the cells in a single row). When the user performs actions on what they see as being selected in the table special code to handle this is triggered that has the smarts to deal with that. This code is currently (as I understand it) disconnected from our standard Range and Selection scripting objects and we don't have any special APIs to help with this stuff.

    I'm hoping we can expose more APIs to make working with tables using script more robust in the future, but for now there are limitations.

    The complicated script below is one way to get around the fact that a script cannot simply move a Range object into a element and then call the method Range.SelectContainerContents() followed by Range.Select() <-- now wouldn't that be nice eh? What it Does:
    The first part of the script manouevers a Range to a spot the user (and therefore Selection) couldn't normally get to, the element. It does this so I can easily count how many entry elements there are in that row. I need to know that so the rest of the script knows when to stop.
    The second part of the script mimics user interaction as closely as possible using APIs that mimic actual keystrokes.

    So, ignoring the first counting bit of the script (because you as a human being can look at the row and count up the cells), what the script is doing is this:

    1) Put selection at start of the first cell in the row.
    2) Press Shift+End to select contents of cell.
    3) Press Shift+Right Arrow as many times as there are cells in the row.

    Uses:
    If your script needs to do anything with this selection after it has been created it may not get too far because (as discussed above) what XMetaL exposes via Range and Selection is different (it is actually going to be the first element in the XML source in this case) while what you see selected on screen is the entire row. So, I wouldn't try to use this as the starting point to do further manipulations on a row (it would be best to use DOM for that and do it all invisibly anyway).

    However, a script that executes immediately before this to manipulate the content of the row (by DOM or other means) could then run this code to bring those changes to the user's attention. The user can interact with this selection themselves as if they did make it themselves (there is no difference here, when the script is done the selection is as “real” as if the user performed the 1,2,3 steps I've listed above).

    [code]//XMetaL Script Language JScript:
    /*Script for selecting a row.
      Note: Your part of the script (before this) must put
      the selection into a table cell inside the row to be
      selected. The selection can also be one or more cells
      or rows and in that case it will basically just
      collapse and select the first row.
    */

    //define element names for lowercase CALS tables
    //modify as needed for your table type
    var rowElemName = “row”;
    var cellElemName = “entry”;

    var rng = ActiveDocument.Range;

    if (rng.InContextOfType(“TableCell”)) {
         //*must* use a Range here to get to the row
         rng.MoveToElement(rowElemName,false);
         var cellCount = rng.ContainerNode.getNodesByXPath(cellElemName).length;
         rng.MoveToElement(cellElemName);
         //*must* turn this into a real selection here
         rng.Select();
         Selection.EndKey(0,1);
         for (i=0;i           Selection.MoveRight(1);
         }
    }[/code]

    Reply

  • You must be logged in to reply to this topic.

Lost Your Password?

Products
Downloads
Support