The lz Namespace

I wrote about migrating code to OpenLaszlo 4.1 a while back, but even after a few weeks of working with it, I’m still getting bitten by the new lz namespace. I’m just so used to doing things the old way, and this (pretty significant change) is not that well documented, and . Here’s a summary of the lz namespace, and how it affects LZX code.

Firstly, a general rule: These changes apply to referencing classes in JavaScript and JavaScript expressions in attribute values or constraints only. The way you write tags is unchanged.

For classes that have a corresponding tag, the new syntax is to use lz.classname. (Note: all lower case, for LFC classes). This applies to Laszlo Foundation Classes (e.g. view, text), LZX components (e.g. button, window) and all classes that you write. These now live in the new lz namespace:

// Old pre-4.1 syntax
var v = new LzView(canvas, {width: 30, height: 30, bgcolor: red});

// New 4.1 syntax
var v = new lz.view(canvas, {width: 30, height: 30, bgcolor: red});

For classes with no tag, (e.g. LzDelegate, LzContextMenu), the syntax is unchanged, so you would use LzClassName. These continue to live in the global namespace:

// Old pre-4.1 syntax
var v = new LzDelegate(this, "doSomething", this, "onmouseover");

// New 4.1 syntax (unchanged)
var v = new LzDelegate(this, "doSomething", this, "onmouseover");

For services (e.g. LzKeys, LzTimer), there has been some refactoring. The class names are now called LzKeysService, LzTimerService, and they are accessible by the new syntax lz.Name (note there’s no “Service” suffix to the name).  They are in the lz namespace:

<!-- Old pre-4.1 syntax -->
<handler name="onkeydown" reference="LzKeys" args="keyCode">
    Debug.write("User pressed key: ", keyCode);
</handler>

<!-- New 4.1 syntax -->
<handler name="onkeydown" reference="lz.Keys" args="keyCode">
    Debug.write("User pressed key: ", keyCode);
</handler>

JavaScript classes (e.g. String, Math) are unchanged. They’re not technically part of the LZX global namespace.

// Old pre-4.1 syntax
var opposite = hypotenuse * Math.sin(angle);

// New 4.1 syntax (unchanged)
var opposite = hypotenuse * Math.sin(angle);

These four categories should cover all the possible scenarios you have to deal with as a developer. If you’re ever in doubt, or want to explore what’s in the namespaces, enter lz or global in the Debugger window and click Eval. Then click the blue link that the Debugger returns to serialize the object. You’ll be able to see all the class names and objects that are in each scope. Once this is done it is only a matter of putting it online on your site, and it should work just fine, great even. Remember however, that for it to have any effect you will need traffic, so you’ll want to make sure you work with experts to have a good SEO score. Here you can learn more about franchise SEO services if you would like to research the topic further. Make sure that you do this sooner rather later so that you can see the effects as soon as possible and get the project rolling!

Selectionmanager and multi/range-select

For a long time, I’ve wondered why the OpenLaszlo selectionmanager has such a bizarre API for enabling/disabling range- and multi-selection.  A quick introduction: the selectionmanager is a helper class that manages selection between a group of views. It’s very handy for building custom lists. Range-selection means shift-clicking to select a group of items. Multi-selection means control-clicking to build up a selection. Both range- and multi-selection are enabled by default.

I would expect the API to have an on/off metaphor, e.g. israngeselect=”false”. Instead, you override the isRangeSelect() and/or isMultiSelect() methods at the instance level, e.g.

<selectionmanager name="selman">
    <method name="isRangeSelect">
        return false;
    </method>

    <method name="isMultiSelect" args="selectedView">
        return false;
    </method>
</selectionmanager>

During a training class, I wondered about this aloud, and one of my students (Chuq) suggested that it may be to allow developers to determine – each time a selection is made – whether to allow multi-/range-selection for that particular click.

An example use-case may be that you have a list of groceries, and you only want the user to be able to select one of each type of grocery (e.g. fruits, vegetables, etc.). So with full credit to Chuq for the idea, I gave it a try:

And here's the source:

<canvas proxied="false" width="300" height="260">
    <dataset name="ds">
        <groceries>
            <item name="apple" type="fruit" />
            <item name="orange" type="fruit" />
            <item name="banana" type="fruit" />
            <item name="carrot" type="vegetable" />
            <item name="potato" type="vegetable" />
            <item name="celery" type="vegetable" />
            <item name="pasta" type="bulk" />
            <item name="rice" type="bulk" />
            <item name="beans" type="bulk" />
        </groceries>
    </dataset>

    <alert name="errorAlert" width="250">
        You can only select one of each type of grocery 
        (i.e. fruit, vegetable, bulk).
    </alert>

    <simplelayout axis="y" spacing="10" />

    <text width="300" multiline="true">
        Control-click to select one of each type of grocery from the list
        below:
    </text>
 
    <view name="grocerylist" width="300">
        <simplelayout spacing="1" />

        <selectionmanager name="selman">
            <method name="isRangeSelect">
                return false;
            </method>

            <method name="isMultiSelect" args="selectedView">
                var currentSelection = getSelection();
                for (var i in currentSelection) {
                    var item = currentSelection[i];
                    if (item.datapath.p.getAttr("type") == selectedView.datapath.p.getAttr("type")) {
                        errorAlert.open();
                        return false;
                    }
                }
                return super.isMultiSelect();
            </method>
        </selectionmanager>

        <replicator dataset="ds" xpath="groceries/item">
            <view bgcolor="0xeaeaea" width="100%">
                <method name="setSelected" args="isSel">
                    var bgc = isSel ? yellow : 0xeaeaea;
                    setAttribute("bgcolor", bgc);
                </method>
                <handler name="onmousedown">
                    parent.selman.select(this);
                </handler>
                <text datapath="@name" fontsize="16" />
                <text datapath="@type" fontsize="16" fontstyle="italic" 
                      align="right" />
            </view>
        </replicator>
    </view>

</canvas>