[Commits] r2217 - in sandbox/camptocamp/geobretagne: examples lib/GeoExt/widgets/tree tests/lib/GeoExt/widgets/tree

commits at geoext.org commits at geoext.org
Thu May 27 11:40:49 CEST 2010


Author: bbinet
Date: 2010-05-27 11:40:48 +0200 (Thu, 27 May 2010)
New Revision: 2217

Added:
   sandbox/camptocamp/geobretagne/examples/tree-tools.html
   sandbox/camptocamp/geobretagne/examples/tree-tools.js
Modified:
   sandbox/camptocamp/geobretagne/lib/GeoExt/widgets/tree/LayerNode.js
   sandbox/camptocamp/geobretagne/tests/lib/GeoExt/widgets/tree/LayerNode.html
Log:
apply and merge patch-139-r1355-A0.diff from ticket #139.

Added: sandbox/camptocamp/geobretagne/examples/tree-tools.html
===================================================================
--- sandbox/camptocamp/geobretagne/examples/tree-tools.html	                        (rev 0)
+++ sandbox/camptocamp/geobretagne/examples/tree-tools.html	2010-05-27 09:40:48 UTC (rev 2217)
@@ -0,0 +1,77 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+    <head>
+        <title>GeoExt Tree Tools</title>
+
+        <script type="text/javascript" src="http://extjs.cachefly.net/builds/ext-cdn-771.js"></script>
+        <link rel="stylesheet" type="text/css" href="http://extjs.cachefly.net/ext-2.2.1/resources/css/ext-all.css" />
+        <link rel="stylesheet" type="text/css" href="http://extjs.cachefly.net/ext-2.2.1/examples/shared/examples.css" />
+
+        <!--
+        <script type"text/javascript" src="../../ext/adapter/ext/ext-base.js"></script>
+        <script type"text/javascript" src="../../ext/ext-all-debug.js"></script>
+        <link rel="stylesheet" type="text/css" href="../../ext/resources/css/ext-all.css"></script>
+        -->
+
+        <script src="http://openlayers.org/api/2.8/OpenLayers.js"></script>
+        <script type="text/javascript" src="../lib/GeoExt.js"></script>
+
+        <script type="text/javascript" src="tree-tools.js"></script>
+
+        <style type="text/css">
+        .gx-tree-layer-actions {
+            float: right;
+        }
+        .gx-tree-layer-action {
+            background-position: center center;
+            background-repeat: no-repeat;
+            border: 0 none;
+            height: 16px;
+            margin: 0;
+            padding: 0;
+            vertical-align: top;
+            width: 16px;
+        }
+        .gx-tree-layer-actions .delete {
+            background: transparent url(resources/img/delete.gif);
+        }
+        .gx-tree-layer-actions .up {
+            background: transparent url(resources/img/move_up.png);
+        }
+        .gx-tree-layer-actions .down {
+            background: transparent url(resources/img/move_down.png);
+        }
+        .gx-tree-layer-actions .tbar {
+            background: transparent url(resources/img/info.png);
+        }
+        .gx-tree-layer-actions .disabled {
+            opacity: 0.2;
+        }
+        .gx-toolbar {
+            background: none;
+            border-style: none;
+            left: 15;
+        }
+        .x-tree-node-el {
+            border-bottom: 1px solid #ddd;
+        }
+        .x-tree-node-collapsed .x-tree-node-icon, .x-tree-node-expanded .x-tree-node-icon, .x-tree-node-leaf .gx-tree-layer-icon {
+           width: 0px; !important;
+        }
+    </style>
+
+    </head>
+    <body>
+        <div id="desc">
+            <h1>GeoExt Tree Node UI</h1>
+
+            <p>This example shows how to add tools (actions) and components in
+            tree nodes. The tools added here allow moving the layers up and
+            down and deleting them. The component added for each node is a
+            toolbar including an opacity slider which acts on the node's
+            layer.</p>
+
+            <p>The js is not minified so it is readable. See
+            <a href="tree-tools.js">tree-tools.js</a>.</p>
+        </div>
+    </body>
+</html>

Added: sandbox/camptocamp/geobretagne/examples/tree-tools.js
===================================================================
--- sandbox/camptocamp/geobretagne/examples/tree-tools.js	                        (rev 0)
+++ sandbox/camptocamp/geobretagne/examples/tree-tools.js	2010-05-27 09:40:48 UTC (rev 2217)
@@ -0,0 +1,233 @@
+/**
+ * Copyright (c) 2008-2009 The Open Source Geospatial Foundation
+ *
+ * Published under the BSD license.
+ * See http://svn.geoext.org/core/trunk/geoext/license.txt for the full text
+ * of the license.
+ */
+
+Ext.namespace("GeoExt.examples");
+
+// this function creates a toolbar with a layer opacity
+// slider and an information button, it is used to
+// configure the layer node ui to add a toolbar
+// for each node in the layer tree
+GeoExt.examples.tbar = function(node, ct) {
+    return new Ext.Toolbar({
+        cls: "gx-toolbar",
+        buttons: [new GeoExt.LayerOpacitySlider({
+            layer: node.layer,
+            aggressive: true,
+            plugins: new GeoExt.LayerOpacitySliderTip(),
+            width: 100
+        })]
+    });
+};
+
+// this function takes action based on the "action"
+// parameter, it is used as a listener to layer
+// nodes' "action" events
+GeoExt.examples.act = function(node, action, evt) {
+    var layer = node.layer;
+    switch(action) {
+    case "down":
+        layer.map.raiseLayer(layer, -1);
+        break;
+    case "up":
+        layer.map.raiseLayer(layer, +1);
+        break;
+    case "delete":
+        layer.destroy();
+        break;
+    }
+};
+
+// a custom layer node UI class, for use with the second tree (see below).
+GeoExt.examples.CustomLayerNodeUI = Ext.extend(GeoExt.tree.LayerNodeUI, {
+    actions: [{
+        action: "delete",
+        qtip: "delete"
+    }, {
+        action: "up",
+        qtip: "move up",
+        update: function(el) {
+            // "this" references the tree node
+            var layer = this.layer, map = layer.map;
+            if (map.getLayerIndex(layer) == map.layers.length - 1) {
+                el.hide();
+            } else {
+                el.show();
+            }
+        }
+    }, {
+        action: "down",
+        qtip: "move down",
+        update: function(el) {
+            // "this" references the tree node
+            var layer = this.layer, map = layer.map;
+            if (map.getLayerIndex(layer) == 1) {
+                el.hide();
+            } else {
+                el.show();
+            }
+        }
+    }],
+    component: GeoExt.examples.tbar
+});
+
+Ext.onReady(function() {
+    Ext.QuickTips.init();
+
+    // the map panel
+    var mapPanel = new GeoExt.MapPanel({
+        border: true,
+        region: "center",
+        center: [146.1569825, -41.6109735],
+        zoom: 6,
+        layers: [
+            new OpenLayers.Layer.WMS("Tasmania State Boundaries",
+                "http://demo.opengeo.org/geoserver/wms", {
+                    layers: "topp:tasmania_state_boundaries"
+                }, {
+                    buffer: 0,
+                    // exclude this layer from layer container nodes
+                    displayInLayerSwitcher: false
+               }),
+            new OpenLayers.Layer.WMS("Water",
+                "http://demo.opengeo.org/geoserver/wms", {
+                    layers: "topp:tasmania_water_bodies",
+                    transparent: true,
+                    format: "image/gif"
+                }, {
+                    buffer: 0
+                }),
+            new OpenLayers.Layer.WMS("Cities",
+                "http://demo.opengeo.org/geoserver/wms", {
+                    layers: "topp:tasmania_cities",
+                    transparent: true,
+                    format: "image/gif"
+                }, {
+                    buffer: 0
+                }),
+            new OpenLayers.Layer.WMS("Tasmania Roads",
+                "http://demo.opengeo.org/geoserver/wms", {
+                    layers: "topp:tasmania_roads",
+                    transparent: true,
+                    format: "image/gif"
+                }, {
+                    buffer: 0
+                })
+        ]
+    });
+
+    // the first layer tree panel. If this tree the node actions and
+    // component are set using the loader's "baseAttrs" property.
+    var tree1 = new Ext.tree.TreePanel({
+        border: true,
+        region: "center",
+        title: "Layer Tree 1",
+        split: true,
+        collapsible: true,
+        autoScroll: true,
+        loader: {
+            applyLoader: false
+        },
+        root: {
+            nodeType: "gx_layercontainer",
+            loader: {
+                baseAttrs: {
+                    actions: [{
+                        action: "delete",
+                        qtip: "delete"
+                    }, {
+                        action: "up",
+                        qtip: "move up",
+                        update: function(el) {
+                            // "this" references the tree node
+                            var layer = this.layer, map = layer.map;
+                            if (map.getLayerIndex(layer) == map.layers.length - 1) {
+                                el.addClass('disabled');
+                            } else {
+                                el.removeClass('disabled');
+                            }
+                        }
+                    }, {
+                        action: "down",
+                        qtip: "move down",
+                        update: function(el) {
+                            // "this" references the tree node
+                            var layer = this.layer, map = layer.map;
+                            if (map.getLayerIndex(layer) == 1) {
+                                el.addClass('disabled');
+                            } else {
+                                el.removeClass('disabled');
+                            }
+                        }
+                    }],
+                    checked: null,
+                    component: GeoExt.examples.tbar
+                }
+            }
+        },
+        rootVisible: false,
+        lines: false,
+        listeners: {
+            action: GeoExt.examples.act
+        }
+    });
+
+    // the second layer tree panel. In this tree the CustomLayerNodeUI
+    // class is used for each node of the layer container.
+    var tree2 = new Ext.tree.TreePanel({
+        border: true,
+        region: "south",
+        height: 300,
+        title: "Layer Tree 2",
+        split: true,
+        collapsible: true,
+        autoScroll: true,
+        loader: {
+            applyLoader: false
+        },
+        root: {
+            nodeType: "gx_layercontainer",
+            loader: {
+                uiProviders: {
+                    "ui": GeoExt.examples.CustomLayerNodeUI
+                },
+                baseAttrs: {
+                    uiProvider: "ui"
+                }
+            }
+        },
+        rootVisible: false,
+        lines: false,
+        listeners: {
+            action: GeoExt.examples.act
+        }
+    });
+
+    // the viewport
+    new Ext.Viewport({
+        layout: "fit",
+        hideBorders: true,
+        items: {
+            layout: "border",
+            deferredRender: false,
+            items: [
+                mapPanel, {
+                region: "west",
+                width: 250,
+                layout: "border",
+                items: [
+                    tree1,
+                    tree2
+                ]
+            }, {
+                region: "east",
+                contentEl: "desc",
+                width: 250
+            }]
+        }
+    });
+});

Modified: sandbox/camptocamp/geobretagne/lib/GeoExt/widgets/tree/LayerNode.js
===================================================================
--- sandbox/camptocamp/geobretagne/lib/GeoExt/widgets/tree/LayerNode.js	2010-05-27 09:31:56 UTC (rev 2216)
+++ sandbox/camptocamp/geobretagne/lib/GeoExt/widgets/tree/LayerNode.js	2010-05-27 09:40:48 UTC (rev 2217)
@@ -14,6 +14,14 @@
  *      Place in a separate file if this should be documented.
  */
 GeoExt.tree.LayerNodeUI = Ext.extend(Ext.tree.TreeNodeUI, {
+
+    /** private: constant[actionsCls]
+     */
+    actionsCls: "gx-tree-layer-actions",
+
+    /** private: constant[actionCls]
+     */
+    actionCls: "gx-tree-layer-action",
     
     /** private: method[constructor]
      */
@@ -25,24 +33,69 @@
      *  :param bulkRender: ``Boolean``
      */
     render: function(bulkRender) {
-        var a = this.node.attributes;
-        if (a.checked === undefined) {
-            a.checked = this.node.layer.getVisibility();
+        var attr = this.node.attributes;
+        if (attr.checked === undefined) {
+            attr.checked = this.node.layer.getVisibility();
         }
+        var rendered = this.rendered;
         GeoExt.tree.LayerNodeUI.superclass.render.apply(this, arguments);
-        var cb = this.checkbox;
-        if(a.checkedGroup) {
-            // replace the checkbox with a radio button
-            var radio = Ext.DomHelper.insertAfter(cb,
-                ['<input type="radio" name="', a.checkedGroup,
-                '_checkbox" class="', cb.className,
-                cb.checked ? '" checked="checked"' : '',
-                '"></input>'].join(""));
-            radio.defaultChecked = cb.defaultChecked;
-            Ext.get(cb).remove();
-            this.checkbox = radio;
+
+        if (!rendered) {
+            var cb = this.checkbox;
+            if(attr.checkedGroup) {
+                // replace the checkbox with a radio button
+                var radio = Ext.DomHelper.insertAfter(cb,
+                    ['<input type="radio" name="', attr.checkedGroup,
+                    '_checkbox" class="', cb.className,
+                    cb.checked ? '" checked="checked"' : '',
+                    '"></input>'].join(""));
+                radio.defaultChecked = cb.defaultChecked;
+                Ext.get(cb).remove();
+                this.checkbox = radio;
+            }
+
+            this.enforceOneVisible();
+
+            var actions = attr.actions || this.actions;
+            if(actions && actions.length > 0) {
+                var html = ['<div class="', this.actionsCls, '">'];
+                for(var i=0,len=actions.length; i<len; i++) {
+                    var a = actions[i];
+                    html = html.concat([
+                        '<img id="'+this.node.id+'_'+a.action,
+                        '" ext:qtip="'+a.qtip,
+                        '" src="'+this.emptyIcon,
+                        '" class="'+this.actionCls+' '+a.action+'" />'
+                    ]);
+                }
+                html.concat(['</div>']);
+                Ext.DomHelper.insertFirst(this.elNode, html.join(""));
+            }
+            this.updateActions();
+
+            var component = attr.component || this.component;
+            if(component) {
+                var elt = Ext.DomHelper.append(this.elNode, [
+                    {"tag": "div"}
+                ]);
+                if(typeof component == "function") {
+                    component = component(this.node, elt);
+                } else if (typeof component == "object" &&
+                           typeof component.fn == "function") {
+                    component = component.fn.apply(
+                        component.scope, [this.node, elt]
+                    );
+                }
+                if(typeof component == "object" &&
+                   typeof component.xtype == "string") {
+                    component = Ext.ComponentMgr.create(component);
+                }
+                if(component instanceof Ext.Component) {
+                    component.render(elt);
+                    this.node.component = component;
+                }
+            }
         }
-        this.enforceOneVisible();
     },
     
     /** private: method[onClick]
@@ -51,10 +104,31 @@
     onClick: function(e) {
         if(e.getTarget('.x-tree-node-cb', 1)) {
             this.toggleCheck(this.isChecked());
+        } else if(e.getTarget('.' + this.actionCls, 1)) {
+            var t = e.getTarget('.' + this.actionCls, 1);
+            var action = t.className.replace(this.actionCls + ' ', '');
+            if (this.fireEvent("action", this.node, action, e) === false) {
+                return;
+            }
         } else {
             GeoExt.tree.LayerNodeUI.superclass.onClick.apply(this, arguments);
         }
     },
+
+    /** private: method[updateActions]
+     *
+     *  Update all the actions.
+     */
+    updateActions: function() {
+        var n = this.node;
+        var actions = n.attributes.actions || this.actions || [];
+        Ext.each(actions, function(a, index) {
+            var el = Ext.get(n.id + '_' + a.action);
+            if (el && typeof a.update == "function") {
+                a.update.call(n, el);
+            }
+        });
+    },
     
     /** private: method[toggleCheck]
      * :param value: ``Boolean``
@@ -79,7 +153,7 @@
             var checkedCount = 0;
             // enforce "not more than one visible"
             Ext.each(checkedNodes, function(n){
-                var l = n.layer
+                var l = n.layer;
                 if(!n.hidden && n.attributes.checkedGroup === group) {
                     checkedCount++;
                     if(l != layer && attributes.checked) {
@@ -175,6 +249,41 @@
      *  :class:`GeoExt.tree.LayerParamLoader` instance will be created, with
      *  the provided object as configuration.
      */
+
+    /** api: config[actions]
+     *  ``Array(Object)`` An array of objects defining actions. An action is a
+     *  clickable image in the node, it is defined with two properties:
+     *  "action" and "qtip".
+     *  * the "action" property provides the name of the action. It is used as
+     *    the name of the ``img`` tag's class. The ``img`` tag being placed in a
+     *    div whose class is "gx-tree-layer-actions" a CSS selector for the
+     *    action is ``.gx-tree-layer-actions .action-name``. The name of the
+     *    action is also set in "action" events for "action" listeners to know
+     *    which action got clicked.
+     *  * the "qtip" property references the tooltip displayed when the action
+     *    image is hovered.
+     *  This property applies only if the node is configured with a
+     *  :class:`GeoExt.tree.LayerNodeUI` UI instance (which is the default).
+     */
+
+    /** api: config[component]
+     *  ``Ext.Component or Object or Function`` This property is to be used
+     *  when an Ext component is to be inserted in the node. This property can
+     *  be used in several ways, it can reference
+     *  * ``Ext.Component`` a component instance. In this case the provided
+     *    component is just rendered in the node.
+     *  * ``Object`` a component config (using ``xtype``). In this case the
+     *    component is instantiated and then rendered in the node.
+     *  * ``Function`` a function returning a component instance or config.
+     *    This function is passed a reference to the layer node and to the Ext
+     *    element (``Ext.Element``) into which the component is to be rendered,
+     *    it must returned a component instance or config.
+     *  * ``Object`` an object with a ``fn`` and ``scope`` properties. ``fn``
+     *    references a function returning a component instance or config (like
+     *    previously), ``scope`` is its execution scope.
+     *  This property applies only if the node is configured with a
+     *  :class:`GeoExt.tree.LayerNodeUI` UI instance (which is the default).
+     */
     
     /** private: method[constructor]
      *  Private constructor override.
@@ -190,6 +299,17 @@
         }
         
         this.defaultUI = this.defaultUI || GeoExt.tree.LayerNodeUI;
+        this.addEvents(
+            /** api: event[action]
+             *  Notifies listeners when an action is clicked, listeners are
+             *  called with the following arguments:
+             *  * :class:`GeoExt.tree.LayerNode` the layer node
+             *  * ``String`` the action name
+             *  * ``Ext.EventObject`` the event object
+             */
+            "action"
+        );
+
         
         Ext.apply(this, {
             layer: config.layer,

Modified: sandbox/camptocamp/geobretagne/tests/lib/GeoExt/widgets/tree/LayerNode.html
===================================================================
--- sandbox/camptocamp/geobretagne/tests/lib/GeoExt/widgets/tree/LayerNode.html	2010-05-27 09:31:56 UTC (rev 2216)
+++ sandbox/camptocamp/geobretagne/tests/lib/GeoExt/widgets/tree/LayerNode.html	2010-05-27 09:40:48 UTC (rev 2217)
@@ -180,7 +180,331 @@
             node.destroy();
             mapPanel.destroy();
         }
-        
+
+        function test_ui_node_action(t) {
+            t.plan(6);
+
+            // setup
+
+            var node = new GeoExt.tree.LayerNode({
+                layer: new OpenLayers.Layer(),
+                actions: [{
+                    action: "foo-action",
+                    qtip: "foo-qtip"
+                }]
+            });
+            var tree  = new Ext.tree.TreePanel({
+                renderTo: "tree",
+                root: node
+            });
+            var ui = node.ui;
+            var elNode = Ext.fly(ui.elNode);
+
+            // test
+
+            t.ok(elNode.first().hasClass(ui.actionsCls),
+                 "the actions div is at correct location and " +
+                 "has a correct class");
+            t.ok(elNode.first().first() &&
+                 elNode.first().first().hasClass(ui.actionCls) &&
+                 elNode.first().first().hasClass("foo-action"),
+                 "the action div is at correct location and " +
+                 "has correct classes");
+
+            // simulate click
+            var log = [];
+            node.on({
+                action: function(n, a, e) {
+                    log.push({n: n, a: a, e: e});
+                }
+            });
+            var e = {
+                getTarget: function(selector) {
+                    if (selector == "." + ui.actionCls) {
+                        return {
+                            className: ui.actionCls + " foo-action"
+                        };
+                    }
+                }
+            };
+            var oc = GeoExt.tree.LayerNodeUI.superclass.onClick;
+            GeoExt.tree.LayerNodeUI.superclass.onClick = function() {};
+            ui.onClick(e);
+            t.eq(log.length, 1,
+                 "click on action img triggers \"action\" event");
+            t.ok(log[0].n == node,
+                 "\"action\" listener given expected node");
+            t.eq(log[0].a, "foo-action",
+                 "\"action\" listener given expected action");
+            t.ok(log[0].e == e,
+                 "\"action\" listener given expected event");
+            GeoExt.tree.LayerNodeUI.superclass.onClick = oc;
+
+            // teardown
+
+            tree.destroy();
+        }
+
+        function test_ui_node_ui_action(t) {
+            t.plan(6);
+
+            // setup
+
+            var UI = Ext.extend(GeoExt.tree.LayerNodeUI, {
+                actions: [{
+                    action: "foo-action",
+                    qtip: "foo-qtip"
+                }]
+            });
+
+            var node = new GeoExt.tree.LayerNode({
+                layer: new OpenLayers.Layer(),
+                uiProvider: UI
+            });
+            var tree  = new Ext.tree.TreePanel({
+                renderTo: "tree",
+                root: node
+            });
+            var ui = node.ui;
+            var elNode = Ext.fly(ui.elNode);
+
+            // test
+
+            t.ok(elNode.first().hasClass(ui.actionsCls),
+                 "the actions div is at correct location and " +
+                 "has a correct class");
+            t.ok(elNode.first().first() &&
+                 elNode.first().first().hasClass(ui.actionCls) &&
+                 elNode.first().first().hasClass("foo-action"),
+                 "the action div is at correct location and " +
+                 "has correct classes");
+
+            // simulate click
+            var log = [];
+            node.on({
+                action: function(n, a, e) {
+                    log.push({n: n, a: a, e: e});
+                }
+            });
+            var e = {
+                getTarget: function(selector) {
+                    if (selector == "." + ui.actionCls) {
+                        return {
+                            className: ui.actionCls + " foo-action"
+                        };
+                    }
+                }
+            };
+            var oc = GeoExt.tree.LayerNodeUI.superclass.onClick;
+            GeoExt.tree.LayerNodeUI.superclass.onClick = function() {};
+            ui.onClick(e);
+            t.eq(log.length, 1,
+                 "click on action img triggers \"action\" event");
+            t.ok(log[0].n == node,
+                 "\"action\" listener given expected node");
+            t.eq(log[0].a, "foo-action",
+                 "\"action\" listener given expected action");
+            t.ok(log[0].e == e,
+                 "\"action\" listener given expected event");
+            GeoExt.tree.LayerNodeUI.superclass.onClick = oc;
+
+            // teardown
+
+            tree.destroy();
+        }
+
+        function test_ui_component_instance(t) {
+            t.plan(4);
+
+            // setup
+
+            var component = new Ext.Panel({
+                id: "foo-id",
+                cls: "foo-cls",
+                ctCls: "foo-ct-cls"
+            });
+            var node = new GeoExt.tree.LayerNode({
+                layer: new OpenLayers.Layer(),
+                component: component
+            });
+            var tree  = new Ext.tree.TreePanel({
+                renderTo: "tree",
+                root: node
+            });
+            var ui = node.ui;
+            var elNode = Ext.fly(ui.elNode);
+
+            // test
+            t.ok(elNode.last().hasClass("foo-ct-cls"),
+                 "the container div is at correct location and " +
+                 "has a correct class");
+            t.ok(elNode.last().child("#foo-id"),
+                 "the container div contains the panel div");
+            t.ok(elNode.last().child("#foo-id") &&
+                 elNode.last().child("#foo-id").hasClass("foo-cls"),
+                 "the panel div has a correct class");
+            t.ok(node.component === component,
+                 "the component is set in the node");
+
+            // teardown
+
+            tree.destroy();
+        }
+
+        function test_ui_component_config(t) {
+            t.plan(3);
+
+            // setup
+
+            var component = {
+                xtype: "panel",
+                cls: "foo-cls",
+                ctCls: "foo-ct-cls"
+            };
+            var node = new GeoExt.tree.LayerNode({
+                layer: new OpenLayers.Layer(),
+                component: component
+            });
+            var tree  = new Ext.tree.TreePanel({
+                renderTo: "tree",
+                root: node
+            });
+            var ui = node.ui;
+            var elNode = Ext.fly(ui.elNode);
+
+            // test
+            t.ok(elNode.last().hasClass("foo-ct-cls"),
+                 "the container div is at correct location and " +
+                 "has a correct class");
+            t.ok(elNode.last().child(".foo-cls") ,
+                 "the container div contains the panel div, " +
+                 "which has a correct class");
+            t.ok(node.component instanceof Ext.Panel,
+                 "the component is set in the node");
+
+            // teardown
+
+            tree.destroy();
+        }
+
+        function test_ui_component_function(t) {
+            t.plan(16);
+
+            // setup
+
+            var component, node, tree, ui, elNode, log;
+
+            // test
+
+            // with a function returning a panel config
+            log = [];
+            component = function(n, e) {
+                log.push({n: n, e: e});
+                return {
+                    xtype: "panel",
+                    cls: "foo-cls",
+                    ctCls: "foo-ct-cls"
+                };
+            };
+            node = new GeoExt.tree.LayerNode({
+                layer: new OpenLayers.Layer(),
+                component: component
+            });
+            tree  = new Ext.tree.TreePanel({
+                renderTo: "tree",
+                root: node
+            });
+            ui = node.ui;
+            elNode = Ext.fly(ui.elNode);
+            t.eq(log.length, 1,
+                 "[1] factory function called once");
+            t.ok(log.length > 0 && log[0].n === node,
+                 "[1] factory function called with node");
+            t.ok(elNode.last().hasClass("foo-ct-cls"),
+                 "[1] the container div is at correct location and " +
+                 "has a correct class");
+            t.ok(elNode.last().child(".foo-cls") ,
+                 "[1] the container div contains the panel div, " +
+                 "which has a correct class");
+            t.ok(node.component instanceof Ext.Panel,
+                 "[1] the component is set in the node");
+            tree.destroy();
+
+            // with a function returning a panel instance
+            log = [];
+            component = function(n, e) {
+                log.push({n: n, e: e});
+                return new Ext.Panel({
+                    cls: "foo-cls",
+                    ctCls: "foo-ct-cls"
+                });
+            };
+            node = new GeoExt.tree.LayerNode({
+                layer: new OpenLayers.Layer(),
+                component: component
+            });
+            tree  = new Ext.tree.TreePanel({
+                renderTo: "tree",
+                root: node
+            });
+            ui = node.ui;
+            elNode = Ext.fly(ui.elNode);
+            t.eq(log.length, 1,
+                 "[2] factory function called once");
+            t.ok(log.length > 0 && log[0].n === node,
+                 "[2] factory function called with node");
+            t.ok(elNode.last().hasClass("foo-ct-cls"),
+                 "[2] the container div is at correct location and " +
+                 "has a correct class");
+            t.ok(elNode.last().child(".foo-cls") ,
+                 "[2] the container div contains the panel div, " +
+                 "which has a correct class");
+            t.ok(node.component instanceof Ext.Panel,
+                 "[2] the component is set in the node");
+            tree.destroy();
+
+            // with an object with fn and scope properties
+            log = [];
+            var scope = {"some": "scope"};
+            component = {
+                fn: function(n, e) {
+                    log.push({n: n, e: e, s: this});
+                    return new Ext.Panel({
+                        cls: "foo-cls",
+                        ctCls: "foo-ct-cls"
+                    });
+                },
+                scope: scope
+            };
+            node = new GeoExt.tree.LayerNode({
+                layer: new OpenLayers.Layer(),
+                component: component
+            });
+            tree  = new Ext.tree.TreePanel({
+                renderTo: "tree",
+                root: node
+            });
+            ui = node.ui;
+            elNode = Ext.fly(ui.elNode);
+            t.eq(log.length, 1,
+                 "[3] factory function called once");
+            t.ok(log.length > 0 && log[0].n === node,
+                 "[3] factory function called with node");
+            t.ok(log.length > 0 && log[0].s === scope,
+                 "[3] factory function called with correct scope");
+            t.ok(elNode.last().hasClass("foo-ct-cls"),
+                 "[3] the container div is at correct location and " +
+                 "has a correct class");
+            t.ok(elNode.last().child(".foo-cls") ,
+                 "[3] the container div contains the panel div, " +
+                 "which has a correct class");
+            t.ok(node.component instanceof Ext.Panel,
+                 "[3] the component is set in the node");
+            tree.destroy();
+
+            // teardown
+        }
+
         </script>
     </head>
     <body>



More information about the Commits mailing list