[Commits] r320 - in sandbox/opengeo/geoexplorer: . build build/apidoc_config examples lib lib/GeoExt/data lib/GeoExt/widgets resources resources/css resources/images resources/images/default resources/images/gray tests tests/lib/GeoExt/data tests/lib/GeoExt/widgets

commits at geoext.org commits at geoext.org
Wed Apr 1 22:02:18 CEST 2009


Author: dwins
Date: 2009-04-01 22:02:18 +0200 (Wed, 01 Apr 2009)
New Revision: 320

Added:
   sandbox/opengeo/geoexplorer/build/apidoc_config/
   sandbox/opengeo/geoexplorer/build/apidoc_config/Languages.txt
   sandbox/opengeo/geoexplorer/build/apidoc_config/Menu.txt
   sandbox/opengeo/geoexplorer/build/apidoc_config/Topics.txt
   sandbox/opengeo/geoexplorer/examples/mappanel-div.js
   sandbox/opengeo/geoexplorer/examples/mappanel-window.js
   sandbox/opengeo/geoexplorer/examples/popup.html
   sandbox/opengeo/geoexplorer/examples/popup.js
   sandbox/opengeo/geoexplorer/lib/GeoExt/data/FeatureRecord.js
   sandbox/opengeo/geoexplorer/lib/GeoExt/widgets/Popup.js
   sandbox/opengeo/geoexplorer/resources/css/popup.css
   sandbox/opengeo/geoexplorer/resources/images/
   sandbox/opengeo/geoexplorer/resources/images/default/
   sandbox/opengeo/geoexplorer/resources/images/default/anchor.png
   sandbox/opengeo/geoexplorer/resources/images/gray/
   sandbox/opengeo/geoexplorer/resources/images/gray/anchor.png
   sandbox/opengeo/geoexplorer/tests/lib/GeoExt/data/FeatureRecord.html
   sandbox/opengeo/geoexplorer/tests/lib/GeoExt/widgets/Popup.html
Modified:
   sandbox/opengeo/geoexplorer/examples/mappanel-div.html
   sandbox/opengeo/geoexplorer/examples/mappanel-window.html
   sandbox/opengeo/geoexplorer/lib/GeoExt.js
   sandbox/opengeo/geoexplorer/lib/GeoExt/data/FeatureReader.js
   sandbox/opengeo/geoexplorer/lib/GeoExt/data/LayerRecord.js
   sandbox/opengeo/geoexplorer/lib/GeoExt/data/LayerStore.js
   sandbox/opengeo/geoexplorer/lib/GeoExt/widgets/MapPanel.js
   sandbox/opengeo/geoexplorer/modifications.txt
   sandbox/opengeo/geoexplorer/resources/css/geoext-all-debug.css
   sandbox/opengeo/geoexplorer/tests/lib/GeoExt/data/FeatureReader.html
   sandbox/opengeo/geoexplorer/tests/list-tests.html
Log:
Merge from trunk, up to r319


Added: sandbox/opengeo/geoexplorer/build/apidoc_config/Languages.txt
===================================================================
--- sandbox/opengeo/geoexplorer/build/apidoc_config/Languages.txt	                        (rev 0)
+++ sandbox/opengeo/geoexplorer/build/apidoc_config/Languages.txt	2009-04-01 20:02:18 UTC (rev 320)
@@ -0,0 +1,113 @@
+Format: 1.4
+
+# This is the Natural Docs languages file for this project.  If you change
+# anything here, it will apply to THIS PROJECT ONLY.  If you'd like to change
+# something for all your projects, edit the Languages.txt in Natural Docs'
+# Config directory instead.
+
+
+# You can prevent certain file extensions from being scanned like this:
+# Ignore Extensions: [extension] [extension] ...
+
+
+#-------------------------------------------------------------------------------
+# SYNTAX:
+#
+# Unlike other Natural Docs configuration files, in this file all comments
+# MUST be alone on a line.  Some languages deal with the # character, so you
+# cannot put comments on the same line as content.
+#
+# Also, all lists are separated with spaces, not commas, again because some
+# languages may need to use them.
+#
+# Language: [name]
+# Alter Language: [name]
+#    Defines a new language or alters an existing one.  Its name can use any
+#    characters.  If any of the properties below have an add/replace form, you
+#    must use that when using Alter Language.
+#
+#    The language Shebang Script is special.  It's entry is only used for
+#    extensions, and files with those extensions have their shebang (#!) lines
+#    read to determine the real language of the file.  Extensionless files are
+#    always treated this way.
+#
+#    The language Text File is also special.  It's treated as one big comment
+#    so you can put Natural Docs content in them without special symbols.  Also,
+#    if you don't specify a package separator, ignored prefixes, or enum value
+#    behavior, it will copy those settings from the language that is used most
+#    in the source tree.
+#
+# Extensions: [extension] [extension] ...
+# [Add/Replace] Extensions: [extension] [extension] ...
+#    Defines the file extensions of the language's source files.  You can
+#    redefine extensions found in the main languages file.  You can use * to
+#    mean any undefined extension.
+#
+# Shebang Strings: [string] [string] ...
+# [Add/Replace] Shebang Strings: [string] [string] ...
+#    Defines a list of strings that can appear in the shebang (#!) line to
+#    designate that it's part of the language.  You can redefine strings found
+#    in the main languages file.
+#
+# Ignore Prefixes in Index: [prefix] [prefix] ...
+# [Add/Replace] Ignored Prefixes in Index: [prefix] [prefix] ...
+#
+# Ignore [Topic Type] Prefixes in Index: [prefix] [prefix] ...
+# [Add/Replace] Ignored [Topic Type] Prefixes in Index: [prefix] [prefix] ...
+#    Specifies prefixes that should be ignored when sorting symbols in an
+#    index.  Can be specified in general or for a specific topic type.
+#
+#------------------------------------------------------------------------------
+# For basic language support only:
+#
+# Line Comments: [symbol] [symbol] ...
+#    Defines a space-separated list of symbols that are used for line comments,
+#    if any.
+#
+# Block Comments: [opening sym] [closing sym] [opening sym] [closing sym] ...
+#    Defines a space-separated list of symbol pairs that are used for block
+#    comments, if any.
+#
+# Package Separator: [symbol]
+#    Defines the default package separator symbol.  The default is a dot.
+#
+# [Topic Type] Prototype Enders: [symbol] [symbol] ...
+#    When defined, Natural Docs will attempt to get a prototype from the code
+#    immediately following the topic type.  It stops when it reaches one of
+#    these symbols.  Use \n for line breaks.
+#
+# Line Extender: [symbol]
+#    Defines the symbol that allows a prototype to span multiple lines if
+#    normally a line break would end it.
+#
+# Enum Values: [global|under type|under parent]
+#    Defines how enum values are referenced.  The default is global.
+#    global       - Values are always global, referenced as 'value'.
+#    under type   - Values are under the enum type, referenced as
+#               'package.enum.value'.
+#    under parent - Values are under the enum's parent, referenced as
+#               'package.value'.
+#
+# Perl Package: [perl package]
+#    Specifies the Perl package used to fine-tune the language behavior in ways
+#    too complex to do in this file.
+#
+#------------------------------------------------------------------------------
+# For full language support only:
+#
+# Full Language Support: [perl package]
+#    Specifies the Perl package that has the parsing routines necessary for full
+#    language support.
+#
+#-------------------------------------------------------------------------------
+
+# The following languages are defined in the main file, if you'd like to alter
+# them:
+#
+#    Text File, Shebang Script, C/C++, C#, Java, JavaScript, Perl, Python,
+#    PHP, SQL, Visual Basic, Pascal, Assembly, Ada, Tcl, Ruby, Makefile,
+#    ActionScript, ColdFusion, R, Fortran
+
+# If you add a language that you think would be useful to other developers
+# and should be included in Natural Docs by default, please e-mail it to
+# languages [at] naturaldocs [dot] org.

Added: sandbox/opengeo/geoexplorer/build/apidoc_config/Menu.txt
===================================================================
--- sandbox/opengeo/geoexplorer/build/apidoc_config/Menu.txt	                        (rev 0)
+++ sandbox/opengeo/geoexplorer/build/apidoc_config/Menu.txt	2009-04-01 20:02:18 UTC (rev 320)
@@ -0,0 +1,72 @@
+Format: 1.4
+
+
+# You can add a title and sub-title to your menu like this:
+# Title: [project name]
+# SubTitle: [subtitle]
+
+# You can add a footer to your documentation like this:
+# Footer: [text]
+# If you want to add a copyright notice, this would be the place to do it.
+
+# You can add a timestamp to your documentation like one of these:
+# Timestamp: Generated on month day, year
+# Timestamp: Updated mm/dd/yyyy
+# Timestamp: Last updated mon day
+#
+#   m     - One or two digit month.  January is "1"
+#   mm    - Always two digit month.  January is "01"
+#   mon   - Short month word.  January is "Jan"
+#   month - Long month word.  January is "January"
+#   d     - One or two digit day.  1 is "1"
+#   dd    - Always two digit day.  1 is "01"
+#   day   - Day with letter extension.  1 is "1st"
+#   yy    - Two digit year.  2006 is "06"
+#   yyyy  - Four digit year.  2006 is "2006"
+#   year  - Four digit year.  2006 is "2006"
+
+
+# --------------------------------------------------------------------------
+# 
+# Cut and paste the lines below to change the order in which your files
+# appear on the menu.  Don't worry about adding or removing files, Natural
+# Docs will take care of that.
+# 
+# You can further organize the menu by grouping the entries.  Add a
+# "Group: [name] {" line to start a group, and add a "}" to end it.
+# 
+# You can add text and web links to the menu by adding "Text: [text]" and
+# "Link: [name] ([URL])" lines, respectively.
+# 
+# The formatting and comments are auto-generated, so don't worry about
+# neatness when editing the file.  Natural Docs will clean it up the next
+# time it is run.  When working with groups, just deal with the braces and
+# forget about the indentation and comments.
+# 
+# --------------------------------------------------------------------------
+
+
+Group: Data  {
+
+   File: FeatureReader  (GeoExt/data/FeatureReader.js)
+   File: FeatureRecord  (GeoExt/data/FeatureRecord.js)
+   File: FeatureStoreMediator  (GeoExt/data/FeatureStoreMediator.js)
+   File: LayerReader  (GeoExt/data/LayerReader.js)
+   File: LayerRecord  (GeoExt/data/LayerRecord.js)
+   File: LayerStoreMediator  (GeoExt/data/LayerStoreMediator.js)
+   File: LayerStoreMixin  (GeoExt/data/LayerStore.js)
+   File: ProtocolProxy  (GeoExt/data/ProtocolProxy.js)
+   }  # Group: Data
+
+File: MapPanel  (GeoExt/widgets/MapPanel.js)
+
+Group: Index  {
+
+   Index: Everything
+   Class Index: Classes
+   Function Index: Functions
+   Property Index: Properties
+   Constructor Index: Constructor
+   XType Index: XTypes
+   }  # Group: Index
+

Added: sandbox/opengeo/geoexplorer/build/apidoc_config/Topics.txt
===================================================================
--- sandbox/opengeo/geoexplorer/build/apidoc_config/Topics.txt	                        (rev 0)
+++ sandbox/opengeo/geoexplorer/build/apidoc_config/Topics.txt	2009-04-01 20:02:18 UTC (rev 320)
@@ -0,0 +1,117 @@
+Format: 1.4
+
+# This is the Natural Docs topics file for this project.  If you change anything
+# here, it will apply to THIS PROJECT ONLY.  If you'd like to change something
+# for all your projects, edit the Topics.txt in Natural Docs' Config directory
+# instead.
+
+
+# If you'd like to prevent keywords from being recognized by Natural Docs, you
+# can do it like this:
+# Ignore Keywords: [keyword], [keyword], ...
+#
+# Or you can use the list syntax like how they are defined:
+# Ignore Keywords:
+#    [keyword]
+#    [keyword], [plural keyword]
+#    ...
+
+
+#-------------------------------------------------------------------------------
+# SYNTAX:
+#
+# Topic Type: [name]
+# Alter Topic Type: [name]
+#    Creates a new topic type or alters one from the main file.  Each type gets
+#    its own index and behavior settings.  Its name can have letters, numbers,
+#    spaces, and these charaters: - / . '
+#
+# Plural: [name]
+#    Sets the plural name of the topic type, if different.
+#
+# Keywords:
+#    [keyword]
+#    [keyword], [plural keyword]
+#    ...
+#    Defines or adds to the list of keywords for the topic type.  They may only
+#    contain letters, numbers, and spaces and are not case sensitive.  Plural
+#    keywords are used for list topics.  You can redefine keywords found in the
+#    main topics file.
+#
+# Index: [yes|no]
+#    Whether the topics get their own index.  Defaults to yes.  Everything is
+#    included in the general index regardless of this setting.
+#
+# Scope: [normal|start|end|always global]
+#    How the topics affects scope.  Defaults to normal.
+#    normal        - Topics stay within the current scope.
+#    start         - Topics start a new scope for all the topics beneath it,
+#                    like class topics.
+#    end           - Topics reset the scope back to global for all the topics
+#                    beneath it.
+#    always global - Topics are defined as global, but do not change the scope
+#                    for any other topics.
+#
+# Class Hierarchy: [yes|no]
+#    Whether the topics are part of the class hierarchy.  Defaults to no.
+#
+# Page Title If First: [yes|no]
+#    Whether the topic's title becomes the page title if it's the first one in
+#    a file.  Defaults to no.
+#
+# Break Lists: [yes|no]
+#    Whether list topics should be broken into individual topics in the output.
+#    Defaults to no.
+#
+# Can Group With: [type], [type], ...
+#    Defines a list of topic types that this one can possibly be grouped with.
+#    Defaults to none.
+#-------------------------------------------------------------------------------
+
+# The following topics are defined in the main file, if you'd like to alter
+# their behavior or add keywords:
+#
+#    Generic, Class, Interface, Section, File, Group, Function, Variable,
+#    Property, Type, Constant, Enumeration, Event, Delegate, Macro,
+#    Database, Database Table, Database View, Database Index, Database
+#    Cursor, Database Trigger, Cookie, Build Target
+
+# If you add something that you think would be useful to other developers
+# and should be included in Natural Docs by default, please e-mail it to
+# topics [at] naturaldocs [dot] org.
+
+
+Topic Type: Constructor
+
+   Class Hierarchy: Yes
+   Keywords:
+      constructor
+      initialize
+      initcomponent
+
+
+Alter Topic Type: Function
+
+   Add Keywords:
+      apimethod
+      apifunction
+
+
+Alter Topic Type: Property
+
+   Add Keywords:
+      apiproperty
+
+
+Topic Type: Node Type
+
+   Plural: Node Types
+   Keywords:
+      nodetype
+
+
+Topic Type: XType
+
+   Plural: XTypes
+   Keywords:
+      xtype

Modified: sandbox/opengeo/geoexplorer/examples/mappanel-div.html
===================================================================
--- sandbox/opengeo/geoexplorer/examples/mappanel-div.html	2009-04-01 19:52:49 UTC (rev 319)
+++ sandbox/opengeo/geoexplorer/examples/mappanel-div.html	2009-04-01 20:02:18 UTC (rev 320)
@@ -1,59 +1,21 @@
 <html>
-  <head>
-    <script type="text/javascript" src="../../../openlayers/lib/OpenLayers.js"></script>
-    <script type="text/javascript" src="../../../ext/2.2.1/adapter/ext/ext-base.js"></script>
-    <script type="text/javascript" src="../../../ext/2.2.1/ext-all-debug.js"></script>
-    <script type="text/javascript" src="../lib/GeoExt.js"></script>
-
-    <link rel="stylesheet" type="text/css" href="../../../ext/2.2.1/resources/css/ext-all.css"></link>
-
-    <script type="text/javascript">
-
-    // this example shows the OpenLayerish way to create a map panel. See
-    // mappanel-window.html for the ExtJSish way to do the same.
-
-    var mapPanel;
-    
-    Ext.onReady(function() {
-        var map = new OpenLayers.Map();
-        var layer = new OpenLayers.Layer.WMS(
-            "bluemarble",
-            "http://sigma.openplans.org/geoserver/wms?",
-            {layers: 'bluemarble'}
-        );
-        map.addLayer(layer);
-
-        mapPanel = new GeoExt.MapPanel({
-            title: "GeoExt MapPanel",
-            renderTo: "mappanel",
-            height: 400,
-            width: 600,
-            map: map,
-            center: new OpenLayers.LonLat(5, 45),
-            zoom: 4
-        });
-    });
-
-    // functions for resizing the map panel
-    function mapSizeUp() {
-        var size = mapPanel.getSize();
-        size.width += 40;
-        size.height += 40;
-        mapPanel.setSize(size);
-    }
-    function mapSizeDown() {
-        var size = mapPanel.getSize();
-        size.width -= 40;
-        size.height -= 40;
-        mapPanel.setSize(size);
-    }
-
-    </script>
-        
-  </head>
-  <body>
-    <div id="mappanel"></div>
-    <input type="button" onclick="mapSizeUp()" value="bigger"></input>
-    <input type="button" onclick="mapSizeDown()" value="smaller"></input>
-  </body>
+    <head>
+        <link rel="stylesheet" type="text/css" href="../../ext/resources/css/ext-all.css"></link>
+        <link rel="stylesheet" type="text/css" href="../../ext/examples/shared/examples.css"></link>
+        <script type="text/javascript" src="../../openlayers/lib/OpenLayers.js"></script>
+        <script type="text/javascript" src="../../ext/adapter/ext/ext-base.js"></script>
+        <script type="text/javascript" src="../../ext/ext-all.js"></script>
+        <script type="text/javascript" src="../lib/GeoExt.js"></script>
+        <script type="text/javascript" src="mappanel-div.js"></script>
+    </head>
+    <body>
+        <h1>GeoExt.MapPanel with an Existing OpenLayers.Map</h1>
+        <p>This example shows the how to create a MapPanel with a map that has
+        already been created.  See <a href="mappanel-window.html">mappanel-window.html</a>
+        for an example that creates the MapPanel without creating the map first.<p>
+        <p>The js is not minified so it is readable. See <a href="mappanel-div.js">mappanel-div.js</a>.</p>
+        <div id="mappanel"></div>
+        <input type="button" onclick="mapSizeUp()" value="bigger"></input>
+        <input type="button" onclick="mapSizeDown()" value="smaller"></input>
+    </body>
 </html>

Added: sandbox/opengeo/geoexplorer/examples/mappanel-div.js
===================================================================
--- sandbox/opengeo/geoexplorer/examples/mappanel-div.js	                        (rev 0)
+++ sandbox/opengeo/geoexplorer/examples/mappanel-div.js	2009-04-01 20:02:18 UTC (rev 320)
@@ -0,0 +1,37 @@
+
+var mapPanel;
+
+Ext.onReady(function() {
+    var map = new OpenLayers.Map();
+    var layer = new OpenLayers.Layer.WMS(
+        "bluemarble",
+        "http://sigma.openplans.org/geoserver/wms?",
+        {layers: 'bluemarble'}
+    );
+    map.addLayer(layer);
+
+    mapPanel = new GeoExt.MapPanel({
+        title: "GeoExt MapPanel",
+        renderTo: "mappanel",
+        height: 400,
+        width: 600,
+        map: map,
+        center: new OpenLayers.LonLat(5, 45),
+        zoom: 4
+    });
+});
+
+// functions for resizing the map panel
+function mapSizeUp() {
+    var size = mapPanel.getSize();
+    size.width += 40;
+    size.height += 40;
+    mapPanel.setSize(size);
+}
+function mapSizeDown() {
+    var size = mapPanel.getSize();
+    size.width -= 40;
+    size.height -= 40;
+    mapPanel.setSize(size);
+}
+

Modified: sandbox/opengeo/geoexplorer/examples/mappanel-window.html
===================================================================
--- sandbox/opengeo/geoexplorer/examples/mappanel-window.html	2009-04-01 19:52:49 UTC (rev 319)
+++ sandbox/opengeo/geoexplorer/examples/mappanel-window.html	2009-04-01 20:02:18 UTC (rev 320)
@@ -1,41 +1,18 @@
 <html>
-  <head>
-    <link rel="stylesheet" type="text/css" href="../../../ext/2.2.1/resources/css/ext-all.css"></link>
-    <script type="text/javascript" src="../../../openlayers/lib/OpenLayers.js"></script>
-    <script type="text/javascript" src="../../../ext/2.2.1/adapter/ext/ext-base.js"></script>
-    <script type="text/javascript" src="../../../ext/2.2.1/ext-all-debug.js"></script>
-    <script type="text/javascript" src="../lib/GeoExt.js"></script>
-
-    <script type="text/javascript">
-
-    // this example shows the Extish way to create a map panel. See
-    // mappanel-div.html for the OpenLayerish way to do the same.
-    
-    var mapPanel;
-    
-    Ext.onReady(function() {
-        new Ext.Window({
-            title: "GeoExt MapPanel Window",
-            height: 400,
-            width: 600,
-            layout: "fit",
-            items: [{
-                xtype: "gx_mappanel",
-                id: "mappanel",
-                layers: [new OpenLayers.Layer.WMS(
-                    "bluemarble",
-                    "http://sigma.openplans.org/geoserver/wms?",
-                    {layers: 'bluemarble'}
-                )],
-                extent: "-5,35,15,55"
-            }]
-        }).show();
-        
-        mapPanel = Ext.getCmp("mappanel");
-    });
-
-    </script>
-  </head>
-  <body>
-  </body>
+    <head>
+        <link rel="stylesheet" type="text/css" href="../../ext/resources/css/ext-all.css"></link>
+        <link rel="stylesheet" type="text/css" href="../../ext/examples/shared/examples.css"></link>
+        <script type="text/javascript" src="../../openlayers/lib/OpenLayers.js"></script>
+        <script type="text/javascript" src="../../ext/adapter/ext/ext-base.js"></script>
+        <script type="text/javascript" src="../../ext/ext-all.js"></script>
+        <script type="text/javascript" src="../lib/GeoExt.js"></script>        
+        <script type="text/javascript" src="mappanel-window.js"></script>
+    </head>
+    <body>
+        <h1>GeoExt.MapPanel in an Ext.Window</h1>
+        <p>This example shows the how to place a MapPanel in another Ext container
+        without creating a map first.  See <a href="mappanel-div.html">mappanel-div.html</a>
+        for an example that creates the map before creating the map panel.<p>
+        <p>The js is not minified so it is readable. See <a href="mappanel-window.js">mappanel-window.js</a>.</p>
+    </body>
 </html>

Added: sandbox/opengeo/geoexplorer/examples/mappanel-window.js
===================================================================
--- sandbox/opengeo/geoexplorer/examples/mappanel-window.js	                        (rev 0)
+++ sandbox/opengeo/geoexplorer/examples/mappanel-window.js	2009-04-01 20:02:18 UTC (rev 320)
@@ -0,0 +1,22 @@
+var mapPanel;
+
+Ext.onReady(function() {
+    new Ext.Window({
+        title: "GeoExt MapPanel Window",
+        height: 400,
+        width: 600,
+        layout: "fit",
+        items: [{
+            xtype: "gx_mappanel",
+            id: "mappanel",
+            layers: [new OpenLayers.Layer.WMS(
+                "bluemarble",
+                "http://sigma.openplans.org/geoserver/wms?",
+                {layers: 'bluemarble'}
+            )],
+            extent: "-5,35,15,55"
+        }]
+    }).show();
+    
+    mapPanel = Ext.getCmp("mappanel");
+});

Added: sandbox/opengeo/geoexplorer/examples/popup.html
===================================================================
--- sandbox/opengeo/geoexplorer/examples/popup.html	                        (rev 0)
+++ sandbox/opengeo/geoexplorer/examples/popup.html	2009-04-01 20:02:18 UTC (rev 320)
@@ -0,0 +1,34 @@
+<html>
+  <head>
+    <title>GeoExt Popup Example</title>
+
+    <link rel="stylesheet" type="text/css" href="../../ext/resources/css/ext-all.css"></link>
+    <link rel="stylesheet" type="text/css" href="../../ext/examples/shared/examples.css"></link>
+    <link rel="stylesheet" type="text/css" href="../resources/css/geoext-all-debug.css" />
+    <script type="text/javascript" src="../../openlayers/lib/OpenLayers.js"></script>
+    <script type="text/javascript" src="../../ext/adapter/ext/ext-base.js"></script>
+    <script type="text/javascript" src="../../ext/ext-all.js"></script>
+    <script>
+    window.scriptLocation = "../lib/";
+    </script>
+    <script type="text/javascript" src="../lib/GeoExt.js"></script>
+    <script type="text/javascript" src="popup.js"></script>
+
+    <style type="text/css">
+    
+    div#map {
+       width: 650px;
+       height: 400px;
+       position: relative;
+    }
+
+    </style>
+  </head>
+  <body>
+    <h1>Popup Example</h1>
+    <p>Click on the point in the map panel to open a popup.
+    The js is not minified so it is readable. See <a href="popup.js">popup.js</a>.</p>
+    <div id="container"></div>
+
+  </body>
+</html>

Added: sandbox/opengeo/geoexplorer/examples/popup.js
===================================================================
--- sandbox/opengeo/geoexplorer/examples/popup.js	                        (rev 0)
+++ sandbox/opengeo/geoexplorer/examples/popup.js	2009-04-01 20:02:18 UTC (rev 320)
@@ -0,0 +1,75 @@
+// make the references to the map panel and the popup 
+// global, this is useful for looking at their states
+// from the console
+var mapPanel, popup;
+
+Ext.onReady(function() {
+
+    // create a vector layer, add a feature into it
+    var vectorLayer = new OpenLayers.Layer.Vector("vector");
+    vectorLayer.addFeatures(
+        new OpenLayers.Feature.Vector(
+            new OpenLayers.Geometry.Point(-45, 5)
+        )
+    );
+
+    // create select feature control
+    var selectCtrl = new OpenLayers.Control.SelectFeature(vectorLayer);
+
+    // define "createPopup" function
+    var bogusMarkup = "Lorem ipsum dolor sit amet, consectetuer adipiscing elit."
+    function createPopup(feature) {
+        popup = new GeoExt.Popup({
+            title: 'My Popup',
+            feature: feature,
+            width:200,
+            html: bogusMarkup,
+            collapsible: true
+        });
+        // unselect feature when the popup
+        // is closed
+        popup.on({
+            close: function() {
+                if(OpenLayers.Util.indexOf(vectorLayer.selectedFeatures,
+                                           this.feature) > -1) {
+                    selectCtrl.unselect(this.feature);
+                }
+            }
+        });
+        popup.addToMapPanel(mapPanel);
+    }
+
+    // create popup on "featureselected"
+    vectorLayer.events.on({
+        featureselected: function(e) {
+            createPopup(e.feature);
+        }
+    });
+
+    // create Ext window including a map panel
+    var mapwin = new Ext.Window({
+        layout: "fit",
+        title: "Map",
+        closeAction: "hide",
+        width: 650,
+        height: 356,
+        x: 50,
+        y: 100,
+        items: {
+            xtype: "gx_mappanel",
+            region: "center",
+            layers: [
+                new OpenLayers.Layer.WMS( 
+                    "OpenLayers WMS",
+                    "http://labs.metacarta.com/wms/vmap0",
+                    {layers: 'basic'} ),
+                vectorLayer
+            ]
+        }
+    });
+    mapwin.show();
+
+    mapPanel = mapwin.items.get(0);
+    mapPanel.map.addControl(selectCtrl);
+    selectCtrl.activate();
+});

Modified: sandbox/opengeo/geoexplorer/lib/GeoExt/data/FeatureReader.js
===================================================================
--- sandbox/opengeo/geoexplorer/lib/GeoExt/data/FeatureReader.js	2009-04-01 19:52:49 UTC (rev 319)
+++ sandbox/opengeo/geoexplorer/lib/GeoExt/data/FeatureReader.js	2009-04-01 20:02:18 UTC (rev 320)
@@ -17,6 +17,10 @@
  * along with GeoExt.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+/**
+ * @include GeoExt/data/FeatureRecord.js
+ */
+
 Ext.namespace('GeoExt', 'GeoExt.data');
 
 /**
@@ -46,9 +50,12 @@
  */
 GeoExt.data.FeatureReader = function(meta, recordType) {
     meta = meta || {};
+    if(!(recordType instanceof Function)) {
+        recordType = GeoExt.data.FeatureRecord.create(
+            recordType || meta.fields || {});
+    }
     GeoExt.data.FeatureReader.superclass.constructor.call(
-        this, meta, recordType || meta.fields
-    );
+        this, meta, recordType);
 };
 
 Ext.extend(GeoExt.data.FeatureReader, Ext.data.DataReader, {

Added: sandbox/opengeo/geoexplorer/lib/GeoExt/data/FeatureRecord.js
===================================================================
--- sandbox/opengeo/geoexplorer/lib/GeoExt/data/FeatureRecord.js	                        (rev 0)
+++ sandbox/opengeo/geoexplorer/lib/GeoExt/data/FeatureRecord.js	2009-04-01 20:02:18 UTC (rev 320)
@@ -0,0 +1,46 @@
+/* Copyright (C) 2008-2009 The Open Source Geospatial Foundation
+ * Published under the BSD license.
+ * See http://geoext.org/svn/geoext/core/trunk/license.txt for the full text
+ * of the license.
+ * 
+ * pending approval */
+
+Ext.namespace("GeoExt.data");
+
+/**
+ * Class: GeoExt.data.FeatureRecord
+ * A subclass of {Ext.data.Record} which provides a special record that
+ * represents an {OpenLayers.Feature}. This record will always have at
+ * least "feature", "fid", and "state" fields in its data. The id of
+ * the record will be the same as the id of the feature it represents.
+ * 
+ * Inherits from
+ * - {Ext.data.Record}
+ */
+GeoExt.data.FeatureRecord = Ext.data.Record.create([
+    {name: "feature"}, {name: "state"}, {name: "fid"}
+]);
+
+/**
+ * APIFunction: GeoExt.data.FeatureRecord.create
+ * Creates a constructor for a FeatureRecord, optionally with additional
+ * fields.
+ * 
+ * Parameters:
+ * o - {Array} Field definition as in {Ext.data.Record.create}. Can be omitted
+ *     if no additional fields are required (records will always have fields
+ *     {OpenLayers.Feature} "feature", {String} "state" and {String} "fid".
+ *
+ * Returns:
+ * {Function} A specialized {<GeoExt.data.FeatureRecord>} constructor.
+ */
+GeoExt.data.FeatureRecord.create = function(o) {
+    var f = Ext.extend(GeoExt.data.FeatureRecord, {});
+    var p = f.prototype;
+    if(o) {
+        for(var i = 0, len = o.length; i < len; i++){
+            p.fields.add(new Ext.data.Field(o[i]));
+        }
+    }
+    return f;
+};

Modified: sandbox/opengeo/geoexplorer/lib/GeoExt/data/LayerRecord.js
===================================================================
--- sandbox/opengeo/geoexplorer/lib/GeoExt/data/LayerRecord.js	2009-04-01 19:52:49 UTC (rev 319)
+++ sandbox/opengeo/geoexplorer/lib/GeoExt/data/LayerRecord.js	2009-04-01 20:02:18 UTC (rev 320)
@@ -17,6 +17,13 @@
  * Inherits from
  * - {Ext.data.Record}
  */
+/**
+ * Constructor: GeoExt.data.LayerRecord
+ * 
+ * Parameters:
+ * data - {Object} data object for the record
+ * id - {String} id of the record
+ */
 GeoExt.data.LayerRecord = Ext.data.Record.create([
     {name: "layer"},
     {name: "title", type: "string", mapping: "name"}
@@ -44,4 +51,4 @@
         }
     }
     return f;
-}
+};

Modified: sandbox/opengeo/geoexplorer/lib/GeoExt/data/LayerStore.js
===================================================================
--- sandbox/opengeo/geoexplorer/lib/GeoExt/data/LayerStore.js	2009-04-01 19:52:49 UTC (rev 319)
+++ sandbox/opengeo/geoexplorer/lib/GeoExt/data/LayerStore.js	2009-04-01 20:02:18 UTC (rev 320)
@@ -8,7 +8,7 @@
 Ext.namespace("GeoExt.data");
 
 /**
- * Class: LayerStoreMixin
+ * Class: GeoExt.data.LayerStoreMixin
  * A store that synchronizes a layers array of an {OpenLayers.Map} with a
  * layer store holding {<GeoExt.data.LayerRecord>} entries.
  * 
@@ -21,14 +21,14 @@
  * });
  * (end)
  * 
- * For convenience, a {GeoExt.data.LayerStore} class is available as a
+ * For convenience, a {<GeoExt.data.LayerStore>} class is available as a
  * shortcut to the Ext.extend sequence in the above code snippet. The above
  * is equivalent to:
  * (start code)
  * var store = new GeoExt.data.LayerStore({
  *     map: myMap,
  *     layers: myLayers
- * })
+ * });
  * (end)
  */
 GeoExt.data.LayerStoreMixin = {
@@ -47,7 +47,7 @@
     reader: null,
 
     /**
-     * Constructor: GeoExt.data.LayerStore
+     * Constructor: GeoExt.data.LayerStoreMixin
      * 
      * Parameters:
      * config - {Object}
@@ -65,9 +65,10 @@
         config = config || {};
         config.reader = config.reader ||
                         new GeoExt.data.LayerReader({}, config.recordType);
+        var map = config.map instanceof GeoExt.MapPanel ?
+                  config.map.map : config.map;
+        delete config.map;
         arguments.callee.superclass.constructor.call(this, config);
-        var map = config.map instanceof GeoExt.MapPanel ?
-            config.map.map : config.map;
         if(map) {
             // create a snapshop of the map's layers
             var layers = map.layers;
@@ -78,32 +79,56 @@
                 this.add((this.reader.readRecords([layer])).records);
             }
 
-            this.setMap(map);
+            this.bind(map);
             config.layers && map.addLayers(config.layers);
         }
     },
-    
+
     /**
-     * APIMethod: setMap
+     * APIMethod: bind
+     * Bind this store to a map instance, once bound the store
+     * is synchronized with the map and vice-versa.
      * 
      * Parameters:
-     * map - {OpenLayers.Map}
+     * map - {OpenLayers.Map} The map instance.
      */
-    setMap: function(map) {
-        this.map = map;
-        map.events.on({
-            "addlayer": this.onAddLayer,
-            "removelayer": this.onRemoveLayer,
-            scope: this
-        });
-        this.on({
-            "add": this.onAdd,
-            "remove": this.onRemove,
-            scope: this
-        });
+    bind: function(map) {
+        if(!this.map) {
+            this.map = map;
+            map.events.on({
+                "addlayer": this.onAddLayer,
+                "removelayer": this.onRemoveLayer,
+                scope: this
+            });
+            this.on({
+                "add": this.onAdd,
+                "remove": this.onRemove,
+                scope: this
+            });
+        }
     },
-    
+
     /**
+     * APIMethod: unbind
+     * Unbind this store from the map it is currently bound.
+     */
+    unbind: function() {
+        if(this.map) {
+            this.map.events.un({
+                "addlayer": this.onAddLayer,
+                "removelayer": this.onRemoveLayer,
+                scope: this
+            });
+            this.un({
+                "add": this.onAdd,
+                "remove": this.onRemove,
+                scope: this
+            });
+            this.map = null;
+        }
+    },
+   
+    /**
      * Method: onAddLayer
      * Handler for a map's addlayer event
      * 
@@ -166,9 +191,21 @@
 
 /**
  * Class: GeoExt.data.LayerStore
- * Default implementation of an {Ext.data.Store} enhanced with
+ * Default implementation of an {Ext.data.Store} extended with
  * {<GeoExt.data.LayerStoreMixin>}
+ * 
+ * Inherits from:
+ * - {Ext.data.Store}
+ * - {<GeoExt.data.LayerStoreMixin>}
  */
+/**
+ * Constructor: GeoExt.data.LayerStore
+ * 
+ * Parameters:
+ * config - {Object} See {<GeoExt.data.LayerStoreMixin>} and 
+ * http://extjs.com/deploy/dev/docs/?class=Ext.data.Store for valid config
+ *     options. 
+ */
 GeoExt.data.LayerStore = Ext.extend(
     Ext.data.Store,
     GeoExt.data.LayerStoreMixin

Modified: sandbox/opengeo/geoexplorer/lib/GeoExt/widgets/MapPanel.js
===================================================================
--- sandbox/opengeo/geoexplorer/lib/GeoExt/widgets/MapPanel.js	2009-04-01 19:52:49 UTC (rev 319)
+++ sandbox/opengeo/geoexplorer/lib/GeoExt/widgets/MapPanel.js	2009-04-01 20:02:18 UTC (rev 320)
@@ -123,6 +123,16 @@
     },
     
     /**
+     * Method: updateMapSize
+     * Tell the map that it needs to recaculate its size and position.
+     */
+    updateMapSize: function() {
+        if(this.map) {
+            this.map.updateSize();
+        }
+    },
+    
+    /**
      * Method: onRender
      *     Private method called after the panel has been
      *     rendered.
@@ -141,6 +151,17 @@
             }
         }
     },
+    
+    /**
+     * Method: afterRender
+     * Private method called after the panel has been rendered.
+     */
+    afterRender: function() {
+        GeoExt.MapPanel.superclass.afterRender.apply(this, arguments);
+        if(this.ownerCt) {
+            this.ownerCt.on("move", this.updateMapSize, this);
+        }
+    },    
 
     /**
      * Method: onResize
@@ -149,7 +170,18 @@
      */
     onResize: function() {
         GeoExt.MapPanel.superclass.onResize.apply(this, arguments);
-        this.map.updateSize();
+        this.updateMapSize();
+    },
+    
+    /**
+     * Method: onDestroy
+     * Private method called during the destroy sequence.
+     */
+    onDestroy: function() {
+        if(this.ownerCt) {
+            this.ownerCt.un("move", this.updateMapSize, this);
+        }
+        GeoExt.MapPanel.superclass.onDestroy.apply(this, arguments);
     }
 });
 
@@ -168,4 +200,7 @@
  	}); 
 }
 
-Ext.reg('gx_mappanel', GeoExt.MapPanel); 
\ No newline at end of file
+/**
+ * XType: gx_mappanel
+ */
+Ext.reg('gx_mappanel', GeoExt.MapPanel); 

Added: sandbox/opengeo/geoexplorer/lib/GeoExt/widgets/Popup.js
===================================================================
--- sandbox/opengeo/geoexplorer/lib/GeoExt/widgets/Popup.js	                        (rev 0)
+++ sandbox/opengeo/geoexplorer/lib/GeoExt/widgets/Popup.js	2009-04-01 20:02:18 UTC (rev 320)
@@ -0,0 +1,392 @@
+Ext.namespace("GeoExt.popup");
+/**
+ * Class: GeoExt.Popup
+ * Popups are a specialized Window that supports anchoring
+ *     to a particular feature in a MapPanel.  When a popup
+ *     is anchored to a feature, that means that the popup
+ *     will visibly point to the feature on the map, and move
+ *     accordingly when the map is panned or zoomed.
+ *
+ * Usage example:
+ * (start code)
+ *
+ * var popup = new GeoExt.Popup({
+ *   title: 'My Popup',
+ *   feature: feature,
+ *   width: 200,
+ *   html: "<div>Popup content</div>",
+ *   collapsible: true
+ * })
+ *
+ * (end)
+ *
+ * Inherits from:
+ * - {Ext.Window}
+ */
+
+/**
+ * Constructor: GeoExt.Popup
+ * 
+ * Parameters:
+ * config - {Object} A config object. In addition to the config options
+ *     of its parent class, this object can receive specific options,
+ *     see the API properties to know about these specific options.
+ */
+GeoExt.Popup = Ext.extend(Ext.Window, {
+
+    /**
+     * APIProperty: anchored
+     * {Boolean} True if this popup begins anchored to
+     * its feature.  Defaults to true.
+     */
+    anchored: true,
+
+    /**
+     * APIProperty: panIn
+     * {Boolean} True if the popup should pan the map so
+     * that the popup is fully in view when it is rendered.  Default is true.
+     */
+    panIn: true,
+
+    /**
+     * APIProperty: unpinnable
+     * {Boolean} True if the popup should have a
+     * "unpin" tool that unanchors it from its feature.
+     * Default is true.
+     */
+    unpinnable: true,
+
+    /**
+     * APIProperty: feature
+     * {OpenLayers.Feature} An OpenLayers feature that is this
+     * popup's anchor. Either this or <lonlat> has to be provided.
+     */
+    feature: null,
+
+    /**
+     * APIProperty: lonlat
+     * {OpenLayers.LonLat} An OpenLayers lonlat from which an
+     * anchor feature's geometry is made if no feature is provided.
+     */
+    lonlat: null,
+
+    /*
+     * Some Ext.Window defaults need to be overriden here
+     * because some Ext.Window behavior is not currently supported.
+     */    
+
+    /**
+     * Property: animCollapse
+     * {Boolean} True to animate the transition when the panel is 
+     * collapsed, false to skip the animation.
+     * Collapsing animation is not supported yet for popups.
+     */
+    animCollapse: false,
+
+    /**
+     * Property: draggable
+     * {Boolean} True to enable dragging of this Panel.
+     * Defaults to false because the popup defaults to being
+     * anchored, and anchored popups should not be draggable.
+     */
+    draggable: false,
+
+    /**
+     * Property: shadow
+     * {Boolean} True to give the popup window a shadow.
+     * Defaults to false because shadows are not supported 
+     * yet for popups (the shadow does not look good with 
+     * the anchor).
+     */
+    shadow: false,
+
+    /**
+     * Property: popupCls
+     * {String} CSS class name for the popup DOM elements.
+     */
+    popupCls: "gx-popup",
+
+    /**
+     * Property: ancCls
+     * {String} CSS class name for the popup's anchor.
+     */
+    ancCls: null,
+
+    /**
+     * Method: initComponent
+     *     Initializes the popup.
+     */
+    initComponent: function() {        
+        if (!this.feature && this.lonlat) {
+            this.feature = new OpenLayers.Feature.Vector(
+                new OpenLayers.Geometry.Point(this.lonlat.lon, this.lonlat.lat)
+            );
+        }
+
+        this.baseCls = this.popupCls + " " + this.baseCls;
+
+        this.elements += ',anc';
+
+        GeoExt.Popup.superclass.initComponent.call(this);
+
+    },
+
+    /**
+     * Method: onRender
+     *     Executes when the popup is rendered.
+     */
+    onRender: function(ct, position) {
+        GeoExt.Popup.superclass.onRender.call(this, ct, position);
+        
+        this.ancCls = this.popupCls + "-anc";
+
+        //create anchor dom element.
+        this.createElement("anc", this.el);
+    },
+
+    /**
+     * Method: initTools
+     *     Initializes the tools on the popup.  In particular,
+     *     it adds the 'unpin' tool if the popup is unpinnable.
+     */
+    initTools : function() {
+        if(this.unpinnable) {
+            this.addTool({
+                id: 'unpin',
+                handler: this.unanchor.createDelegate(this, [])
+            });
+        }
+
+        GeoExt.Popup.superclass.initTools.call(this);
+    },
+
+    /**
+     * APIMethod: addToMapPanel
+     *      Adds this popup to a MapPanel.  Assumes that the
+     *      MapPanel's map is already initialized and that the
+     *      Popup's feature is on the map.
+     * 
+     * Parameters:
+     * mapPanel - {<GeoExt.MapPanel>} a MapPanel to which to
+     *     add this popup.
+     */
+    addToMapPanel: function(mapPanel) {
+        this.mapPanel = mapPanel;
+        this.map = this.mapPanel.map;
+
+        mapPanel.add(this);
+        mapPanel.doLayout();
+
+        this.position();
+
+        /* Anchoring */
+        if(this.anchored) {
+            this.anchor();
+        }
+
+        this.show();
+
+        /* Panning */
+        if(this.panIn) {
+            this.panIntoView();
+        }
+    },
+
+    /**
+     * Method: setSize
+     *     Sets the size of the popup, taking into account
+     *     the size of the anchor.
+     *     
+     * Parameters:
+     * w - {Integer}
+     * h - {Integer}
+     */
+    setSize: function(w, h) {
+        if(this.anc) {
+            var ancSize = this.getAnchorElement().getSize();
+            
+            if(typeof w == 'object') {
+                h = w.height - ancSize.height;
+                w = w.width;
+            } else {
+                h = h - ancSize.height;
+            }
+        }
+        GeoExt.Popup.superclass.setSize.call(this, w, h);
+    },
+
+    /**
+     * Method: position
+     *     Positions the popup relative to its feature
+     */
+    position: function() {
+        var centerLonLat = this.feature.geometry.getBounds().getCenterLonLat();
+        var centerPx = this.map.getViewPortPxFromLonLat(centerLonLat);
+
+        //This works for positioning with the anchor on the bottom.
+        
+        //Will have to functionalize this out later and allow
+        //for other positions relative to the feature.
+        var anchorSelector = "div." + this.ancCls;
+
+        var dx = this.anc.down(anchorSelector).getLeft(true) +
+                            this.anc.down(anchorSelector).getWidth() / 2;
+        var dy = this.el.getHeight();
+
+        //Assuming for now that the map viewport takes up
+        //the entire area of the MapPanel
+        this.setPosition(centerPx.x - dx, centerPx.y - dy);
+    },
+
+    /**
+     * Method: getAnchorElement
+     *     Returns the anchor element of the popup
+     *
+     * Returns:
+     * {Ext.Element}
+     */
+    getAnchorElement: function() {
+        var anchorSelector = "div." + this.ancCls;
+        var anc = Ext.get(this.el.child(anchorSelector));
+        return anc;
+    },
+
+    /**
+     * Method: position
+     *     Anchors a popup to its feature
+     *     by registering listeners that reposition the popup
+     *     when the map is moved.
+     */
+    anchor: function() {
+        this.map.events.on({
+            "move" : this.position,
+            scope : this            
+        });
+
+        this.on({
+            "resize": this.position,
+            "collapse": this.position,
+            "expand": this.position,
+            scope: this
+        });
+    },
+
+    /**
+     * APIMethod: unanchor
+     *     Unanchors a popup from its feature.
+     *     Currently, this removes the popup from its MapPanel
+     *     and adds it to the page body.
+     */
+    unanchor: function() {
+        this.unbindFromMapPanel();
+
+        //make the window draggable
+        this.draggable = true;
+        this.header.addClass("x-window-draggable");
+        this.dd = new Ext.Window.DD(this);
+
+        //remove anchor
+        this.getAnchorElement().remove();
+        this.anc = null;
+
+        //hide unpin tool
+        this.tools.unpin.hide();
+
+        //keep track of whether the popup has been collapsed
+        var collapsed = this.collapsed;
+
+        //Steps to move this window out to the body
+        //TODO: Make 'unpinned' container configurable
+        this.mapPanel.remove(this, false);
+
+        this.container = Ext.getBody()
+        
+        var xy = this.getPosition();
+        this.hide();
+        this.el.appendTo(Ext.getBody());
+        this.setPagePosition(xy[0],xy[1]);
+        this.show();
+
+        //recollapse if it was collapsed before
+        if(collapsed) {
+            this.collapse();
+        }
+    },
+
+    /** Method: unbindFromMapPanel
+     *      Utility method for unbinding events that call for
+     *      popup repositioning.
+     */
+    unbindFromMapPanel: function() {
+        //stop position with feature
+        this.map.events.un({
+            "move" : this.position,
+            scope : this
+        });
+
+        this.un("resize", this.position);
+        this.un("collapse", this.position);
+        this.un("expand", this.position);
+    },
+
+    /**
+     *  APIMethod: panIntoView
+     *      Pans the MapPanel's map so that an anchored popup
+     *      can come entirely into view, with padding specified
+     *      as per normal OpenLayers.Map popup padding.
+     */ 
+    panIntoView: function() {
+        if(!this.anchored) {
+            /*
+             * If it's not anchored, panning the map won't put popup into view
+             */
+            return;
+        }
+        this.position();
+        
+        var centerLonLat = this.feature.geometry.getBounds().getCenterLonLat(); 
+        var centerPx = this.map.getViewPortPxFromLonLat(centerLonLat);
+
+        //assumed viewport takes up whole body element of map panel
+        var popupPos =  this.getPosition(true);
+       
+        var panelSize = [this.mapPanel.getInnerWidth(), this.mapPanel.getInnerHeight()]; // [X,Y]
+
+        var popupSize = this.getSize();
+
+        var newPos = [popupPos[0], popupPos[1]];
+
+        //For now, using native OpenLayers popup padding.  This may not be ideal.
+        var padding = this.map.paddingForPopups;
+
+        // X
+        if(popupPos[0] < padding.left) {
+            newPos[0] = padding.left;
+        } else if(popupPos[0] + popupSize.width > panelSize[0] - padding.right) {
+            newPos[0] = panelSize[0] - padding.right - popupSize.width;
+        }
+
+        // Y
+        if(popupPos[1] < padding.top) {
+            newPos[1] = padding.top;
+        } else if(popupPos[1] + popupSize.height > panelSize[1] - padding.bottom) {
+            newPos[1] = panelSize[1] - padding.bottom - popupSize.height;
+        }
+
+        var dx = popupPos[0] - newPos[0];
+        var dy = popupPos[1] - newPos[1];
+
+        this.map.pan(dx, dy);
+    },
+
+    /**
+     * Method: beforeDestroy
+     *     Cleanup events before destroying the popup.
+     */
+    beforeDestroy: function() {
+        this.unbindFromMapPanel();
+        GeoExt.Popup.superclass.beforeDestroy.call(this);
+    }
+});
+
+Ext.reg('gx_popup', GeoExt.Popup); 

Modified: sandbox/opengeo/geoexplorer/lib/GeoExt.js
===================================================================
--- sandbox/opengeo/geoexplorer/lib/GeoExt.js	2009-04-01 19:52:49 UTC (rev 319)
+++ sandbox/opengeo/geoexplorer/lib/GeoExt.js	2009-04-01 20:02:18 UTC (rev 320)
@@ -58,6 +58,7 @@
      */
     if(!singleFile) {
         var jsfiles = new Array(
+            "GeoExt/data/FeatureRecord.js",
             "GeoExt/data/FeatureReader.js",
             "GeoExt/data/FeatureStoreMediator.js",
             "GeoExt/data/LayerRecord.js",
@@ -68,6 +69,7 @@
             "GeoExt/data/WMSCapabilitiesReader.js",
             "GeoExt/data/WMSCapabilitiesStore.js",
             "GeoExt/widgets/MapPanel.js",
+            "GeoExt/widgets/Popup.js",
             "GeoExt/widgets/tree/TristateCheckboxNode.js",
             "GeoExt/widgets/tree/TristateCheckboxNodeUI.js",
             "GeoExt/widgets/tree/LayerNode.js",

Modified: sandbox/opengeo/geoexplorer/modifications.txt
===================================================================
--- sandbox/opengeo/geoexplorer/modifications.txt	2009-04-01 19:52:49 UTC (rev 319)
+++ sandbox/opengeo/geoexplorer/modifications.txt	2009-04-01 20:02:18 UTC (rev 320)
@@ -6,4 +6,5 @@
  * Add WMSCapabilitiesStore (see #9)
  * Added examples of grid using WMSCapabilitiesStore (see #9)
  * Allow array extent or center in MapPanel (see #31)
+ * Merge changes from trunk up to r319
 

Modified: sandbox/opengeo/geoexplorer/resources/css/geoext-all-debug.css
===================================================================
--- sandbox/opengeo/geoexplorer/resources/css/geoext-all-debug.css	2009-04-01 19:52:49 UTC (rev 319)
+++ sandbox/opengeo/geoexplorer/resources/css/geoext-all-debug.css	2009-04-01 20:02:18 UTC (rev 320)
@@ -1,2 +1,2 @@
 @import "example.css";
-
+ at import "popup.css";

Added: sandbox/opengeo/geoexplorer/resources/css/popup.css
===================================================================
--- sandbox/opengeo/geoexplorer/resources/css/popup.css	                        (rev 0)
+++ sandbox/opengeo/geoexplorer/resources/css/popup.css	2009-04-01 20:02:18 UTC (rev 320)
@@ -0,0 +1,21 @@
+
+.gx-popup-anc {
+	background: transparent url(../images/default/anchor.png) no-repeat 0 0;
+        position: relative;
+        top:-1px;
+        left:5px;
+        z-index:2;
+        height:16px;
+        width:31px;
+}
+
+
+.xtheme-gray .gx-popup-anc {
+	background: transparent url(../images/gray/anchor.png) no-repeat 0 0;
+        position: relative;
+        top:-1px;
+        left:5px;
+        z-index:2;
+        height:16px;
+        width:31px;
+}
\ No newline at end of file

Added: sandbox/opengeo/geoexplorer/resources/images/default/anchor.png
===================================================================
--- sandbox/opengeo/geoexplorer/resources/images/default/anchor.png	                        (rev 0)
+++ sandbox/opengeo/geoexplorer/resources/images/default/anchor.png	2009-04-01 20:02:18 UTC (rev 320)
@@ -0,0 +1,5 @@
+‰PNG
+
+   
+IHDR         îø¤ì   tEXtSoftware Adobe ImageReadyqÉe<  IDATxÚblYp$Ÿ‘‘1'ÎÛàç÷ߌo>~ûËÏÀÀðŠhŠŠ$ÇýO_r,ÞzAȝÎ$&þÿÿÊ¢­ØY˜þKós1d åcýl1È^&¨ØËw\`€:àµ-fdøóÙb8’t|¦¥Åè–3¸ÛêSÕø,Æ°‡¾PÃb¹èj˜°iDw ‰!@ŒÅ8-Gw +Ób@¬Åx-'ǤXLÐrR@ªÅDYŽÅRè Çb¢-Gs ²ȵe;©¹V|ãábc™·qåcªù½$Ö\_~¼´X‹A€…ÌÂä †MoTÙ½äXL‰åPñ)r
+ 0 :~çÔˆÁ7    IEND®B`‚
\ No newline at end of file

Added: sandbox/opengeo/geoexplorer/resources/images/gray/anchor.png
===================================================================
--- sandbox/opengeo/geoexplorer/resources/images/gray/anchor.png	                        (rev 0)
+++ sandbox/opengeo/geoexplorer/resources/images/gray/anchor.png	2009-04-01 20:02:18 UTC (rev 320)
@@ -0,0 +1,7 @@
+‰PNG
+
+   
+IHDR         îø¤ì   tEXtSoftware Adobe ImageReadyqÉe<  "IDATxÚ¬”½‚0…KCü	‹“£Ž:G^ƒ—„×`dô\Üý‹J=—\Mm°ÐÚ“œ0pÏýMJ¤”EQTišŠ$I4ƒÇð¾ÁWø.Üñž	<‚|‚ÎeYŠ,ËvÁI\ FYtn6¶,À1À·íÞp.°Gð“iè/ø
+ð	àÍg@‡s
+HxpðRf‚0¨hD a¤}&¸Î\à¼èz/XýsxõkFÚ ¸æ®`ÁàµmNö-‚-ÝË¡Üæúf吅t/‡ÐÀ»A×Á¼j6iÂiøâv†æøè
+ö‚œúK÷qžçU]×=}wxÃßþÉ{{(½ úµŠø(ù®    IEND®B`‚
\ No newline at end of file

Modified: sandbox/opengeo/geoexplorer/tests/lib/GeoExt/data/FeatureReader.html
===================================================================
--- sandbox/opengeo/geoexplorer/tests/lib/GeoExt/data/FeatureReader.html	2009-04-01 19:52:49 UTC (rev 319)
+++ sandbox/opengeo/geoexplorer/tests/lib/GeoExt/data/FeatureReader.html	2009-04-01 20:02:18 UTC (rev 320)
@@ -16,9 +16,9 @@
             ]);
             var fields = reader.recordType.prototype.fields;
             // 2 tests
-            t.eq(fields.items.length, 2, 'number of items is correct');
-            t.ok(fields.items[0].name == 'foo' &&
-                 fields.items[1].name == 'bar',
+            t.eq(fields.items.length, 5, 'number of items is correct');
+            t.ok(fields.items[3].name == 'foo' &&
+                 fields.items[4].name == 'bar',
                  'field values are correct');
         }
         function test_readRecords(t) {

Added: sandbox/opengeo/geoexplorer/tests/lib/GeoExt/data/FeatureRecord.html
===================================================================
--- sandbox/opengeo/geoexplorer/tests/lib/GeoExt/data/FeatureRecord.html	                        (rev 0)
+++ sandbox/opengeo/geoexplorer/tests/lib/GeoExt/data/FeatureRecord.html	2009-04-01 20:02:18 UTC (rev 320)
@@ -0,0 +1,53 @@
+<!DOCTYPE html>
+<html debug="true">
+  <head>
+    <script type="text/javascript" src="../../../../../ext/adapter/ext/ext-base.js"></script>
+    <script type="text/javascript" src="../../../../../ext/ext-all-debug.js"></script>
+
+    <script type="text/javascript" src="../../../../../openlayers/lib/OpenLayers.js"></script>
+    <script type="text/javascript" src="../../../../lib/GeoExt.js"></script>
+
+    <script type="text/javascript">
+       
+        function test_featurerecord(t) {
+            t.plan(14);
+
+            var c, feature, record;
+            
+            c = GeoExt.data.FeatureRecord.create();
+            t.ok(c instanceof Function, "create returns a func");
+            t.eq(c.prototype.fields.items[0].name, "feature",
+                 "\"create\" returns a func with a \"feature\" field in its prototype"); 
+            t.eq(c.prototype.fields.items[1].name, "state",
+                 "\"create\" returns a func with a \"state\" field in its prototype"); 
+            t.eq(c.prototype.fields.items[2].name, "fid",
+                 "\"create\" returns a func with a \"fid\" field in its prototype"); 
+
+            c = GeoExt.data.FeatureRecord.create([
+                {name: "extra1"}, {name: "extra2"}
+            ]);
+            t.eq(c.prototype.fields.items[0].name, "feature",
+                 "\"create(o)\" returns a func with a \"feature\" field in its prototype"); 
+            t.eq(c.prototype.fields.items[1].name, "state",
+                 "\"create(o)\" returns a func with a \"state\" field in its prototype"); 
+            t.eq(c.prototype.fields.items[2].name, "fid",
+                 "\"create(o)\" returns a func with a \"fid\" field in its prototype"); 
+            t.eq(c.prototype.fields.items[3].name, "extra1",
+                 "\"create(o)\" returns a func with a \"extra1\" field in its prototype"); 
+            t.eq(c.prototype.fields.items[4].name, "extra2",
+                 "\"create(o)\" returns a func with a \"extra2\" field in its prototype"); 
+
+            feature = new OpenLayers.Feature();
+            record = new c({feature: feature, state: feature.state, fid: feature.fid}, feature.id);
+            t.ok(record instanceof GeoExt.data.FeatureRecord, "create returns a constructor (FeatureRecord)");
+            t.ok(record instanceof c, "create returns a constructor (c)");
+            t.eq(record.get("feature").id, feature.id, "feature stored correctly");
+            t.eq(record.id, feature.id, "id set correctly");
+            record = new c({feature: feature, state: feature.name, fid: feature.fid, foo: "bar"}, feature.id);
+            t.eq(record.get("foo"), "bar", "foo data row set correctly");
+        }
+    </script>
+  <body>
+    <div id="mappanel"></div>
+  </body>
+</html>

Added: sandbox/opengeo/geoexplorer/tests/lib/GeoExt/widgets/Popup.html
===================================================================
--- sandbox/opengeo/geoexplorer/tests/lib/GeoExt/widgets/Popup.html	                        (rev 0)
+++ sandbox/opengeo/geoexplorer/tests/lib/GeoExt/widgets/Popup.html	2009-04-01 20:02:18 UTC (rev 320)
@@ -0,0 +1,188 @@
+<!DOCTYPE html>
+<html debug="true">
+  <head>
+    <script type="text/javascript" src="../../../../../openlayers/lib/OpenLayers.js"></script>
+    <script type="text/javascript" src="../../../../../ext/adapter/ext/ext-base.js"></script>
+    <script type="text/javascript" src="../../../../../ext/ext-all-debug.js"></script>
+    <script type="text/javascript" src="../../../../lib/GeoExt.js"></script>
+
+
+    <script type="text/javascript">
+
+        function makeFeature() {
+           return new OpenLayers.Feature.Vector(
+              new OpenLayers.Geometry.Point(100,50),
+              {
+                  name : "My Feature"
+              }
+           )
+        }
+
+        function setupContext() {
+            var map = new OpenLayers.Map({
+                projection: new OpenLayers.Projection("EPSG:4326"),                 
+            })
+
+            var vector = new OpenLayers.Layer.Vector("Vector Layer",{
+                styleMap: new OpenLayers.StyleMap()
+            });
+
+            var feature = makeFeature();
+        
+            vector.addFeatures(feature);
+            map.addLayers([
+               new OpenLayers.Layer.WMS( 
+                   "OpenLayers WMS",
+                   "http://labs.metacarta.com/wms/vmap0",
+                   {layers: 'basic'} ),
+               vector
+            ]);
+
+            var view = new Ext.Viewport({
+                layout : "border",
+                items : [{
+                    xtype: "gx_mappanel",
+                    region: "center",
+                    map : map
+                }]
+            });
+
+            return {
+               feature : feature,
+               vector : vector,
+               map : map,
+               mapPanel : view.items.items[0],
+               view : view
+            };
+           
+        }
+
+        function popup(feature){
+          pop = new GeoExt.Popup({
+            title: 'My Popup',
+            feature: feature,
+            width:200,
+            html: bogusMarkup,
+            collapsible: true
+          });
+
+          return pop;
+        }
+
+        var bogusMarkup = "Lorem ipsum dolor sit amet, consectetuer adipiscing elit."
+
+        function test_addtomappanel(t) {
+            t.plan(1);
+
+            var context = setupContext();
+
+            var pop = popup(context.feature, context.mapPanel);
+
+            pop.addToMapPanel(context.mapPanel);
+
+            t.ok(context.mapPanel.el.child("div." + pop.popupCls),"Map panel contains popup");
+        }
+
+        function test_anchor(t) {
+            t.plan(4);
+
+            var context = setupContext();
+
+            var pop = popup(context.feature, context.mapPanel);
+
+            pop.addToMapPanel(context.mapPanel);
+
+            pop.on({
+                'move' : function(c,x,y){
+                    t.ok(true,"Move event fired on " + action); //should happen twice, on call to position()
+                },
+                scope : this
+            });
+
+            t.ok(pop.getAnchorElement(), "Popup has anchor element");
+
+            var action = "map move";
+            context.map.events.triggerEvent("move");
+            
+            action = "popup collapse";
+            pop.collapse();
+
+            action = "popup expand"
+            pop.expand();
+        }
+
+
+        function test_unanchor(t) {
+            t.plan(6);
+
+            var context = setupContext();
+
+            var pop = popup(context.feature, context.mapPanel);
+
+            pop.addToMapPanel(context.mapPanel);
+        
+            pop.collapse();
+
+            var origPos = pop.getPosition();
+
+            pop.unanchor();
+
+            var newPos = pop.getPosition();
+
+            t.ok(!pop.getAnchorElement(),"Anchor element removed");
+            t.ok(!this.collapsed, "Preserved collapsed state");
+            t.ok(!context.mapPanel.el.child("div." + pop.popupCls),"Map panel does not contain popup");
+            t.ok(Ext.getBody().child("div." + pop.popupCls),"Document body contains popup element");
+            t.eq(origPos[0],newPos[0],"Popup remains in same position (X)");
+            t.eq(origPos[1],newPos[1],"Popup remains in same position (Y)");
+
+            pop.on({
+                'move' : function(c,x,y){
+                    t.ok(false,"Move event fired improperly on " + action); //should happen twice, on call to position()
+                },
+                scope : this
+            });
+
+            var action = "map move";
+            context.map.events.triggerEvent("move");
+
+            action = "popup expand"
+            pop.expand();
+            
+            action = "popup collapse";
+            pop.collapse();
+
+        }
+
+        function test_Popup_beforeDestroy(t){
+
+            t.plan(0);
+
+            var context = setupContext();
+            var pop = popup(context.feature, context.mapPanel);
+            pop.addToMapPanel(context.mapPanel);
+
+            pop.on({
+                'move' : function(c,x,y){
+                    t.ok(false,"Move event fired improperly on " + action); //should happen twice, on call to position()
+                },
+                scope : this
+            });
+
+            pop.beforeDestroy();
+
+            var action = "map move";
+            context.map.events.triggerEvent("move");
+
+            action = "popup expand"
+            pop.expand();
+            
+            action = "popup collapse";
+            pop.collapse();
+        }
+
+    </script>
+  <body>
+    <div id="map"></div>
+  </body>
+</html>

Modified: sandbox/opengeo/geoexplorer/tests/list-tests.html
===================================================================
--- sandbox/opengeo/geoexplorer/tests/list-tests.html	2009-04-01 19:52:49 UTC (rev 319)
+++ sandbox/opengeo/geoexplorer/tests/list-tests.html	2009-04-01 20:02:18 UTC (rev 320)
@@ -1,4 +1,5 @@
 <ul id="testlist">
+  <li>lib/GeoExt/data/FeatureRecord.html</li>
   <li>lib/GeoExt/data/FeatureReader.html</li>
   <li>lib/GeoExt/data/FeatureStoreMediator.html</li>
   <li>lib/GeoExt/data/LayerRecord.html</li>
@@ -7,4 +8,5 @@
   <li>lib/GeoExt/data/LayerStoreMediator.html</li>
   <li>lib/GeoExt/data/ProtocolProxy.html</li>
   <li>lib/GeoExt/widgets/MapPanel.html</li>
+  <li>lib/GeoExt/widgets/Popup.html</li>
 </ul>



More information about the Commits mailing list