[OpenLayers-Commits] r3164 - in sandbox/tschaub/geojson: examples lib lib/Firebug lib/OpenLayers lib/OpenLayers/Format

commits at openlayers.org commits at openlayers.org
Wed May 23 18:54:23 EDT 2007


Author: tschaub
Date: 2007-05-23 18:54:22 -0400 (Wed, 23 May 2007)
New Revision: 3164

Added:
   sandbox/tschaub/geojson/lib/Firebug/
   sandbox/tschaub/geojson/lib/Firebug/DebugOpenLayers.js
   sandbox/tschaub/geojson/lib/Firebug/errorIcon.png
   sandbox/tschaub/geojson/lib/Firebug/firebug.css
   sandbox/tschaub/geojson/lib/Firebug/firebug.html
   sandbox/tschaub/geojson/lib/Firebug/firebug.js
   sandbox/tschaub/geojson/lib/Firebug/firebugx.js
   sandbox/tschaub/geojson/lib/Firebug/infoIcon.png
   sandbox/tschaub/geojson/lib/Firebug/warningIcon.png
Modified:
   sandbox/tschaub/geojson/examples/geojson.html
   sandbox/tschaub/geojson/lib/OpenLayers/BaseTypes.js
   sandbox/tschaub/geojson/lib/OpenLayers/Format/GeoJSON.js
Log:
support for RFC-2 - read/write Point, MultiPoint, LineString, MultiLineString, Polygon, MultiPolygon, Box, GeometryCollection, Feature, and FeatureCollection - debugging framework also included

Modified: sandbox/tschaub/geojson/examples/geojson.html
===================================================================
--- sandbox/tschaub/geojson/examples/geojson.html	2007-05-23 20:18:45 UTC (rev 3163)
+++ sandbox/tschaub/geojson/examples/geojson.html	2007-05-23 22:54:22 UTC (rev 3164)
@@ -13,20 +13,27 @@
             height: 350px;
             border: 1px solid gray;
         }
+        #controls {
+            width: 512px;
+        }
+        #geoJSONInput {
+            float: right;
+        }
         #controlToggle li {
             list-style: none;
         }
     </style>
     <script src="../lib/OpenLayers.js"></script>
+    <script src="../lib/Firebug/DebugOpenLayers.js"></script>
     <script type="text/javascript">
         <!--
-        var map, drawControls, geojson;
+        var map, drawControls, geojson, vectors;
         function init(){
             map = new OpenLayers.Map('map');
             var wms = new OpenLayers.Layer.WMS( "OpenLayers WMS", 
                 "http://labs.metacarta.com/wms/vmap0?", {layers: 'basic'}); 
 
-            var vectors = new OpenLayers.Layer.Vector("Vector Layer");
+            vectors = new OpenLayers.Layer.Vector("Vector Layer");
 
             map.addLayers([wms, vectors]);
             map.addControl(new OpenLayers.Control.LayerSwitcher());
@@ -69,11 +76,32 @@
         }
         
         function displayGeoJSON(feature) {
-            var json = geojson.write([feature]);
+            var json = geojson.write(feature);
             // not a good idea in general, just for this demo
             json = json.replace(/,/g, ', ');
             document.getElementById('info').innerHTML = json;
         }
+
+        function parseGeoJSON() {
+            var element = document.getElementById('geojson');
+            var features = geojson.read(element.value, "FeatureCollection");
+            if(features) {
+                var bounds;
+                for(var i=0; i<features.length; ++i) {
+                    if (!bounds) {
+                        bounds = features[i].geometry.getBounds();
+                    } else {
+                        bounds.extend(features[i].geometry.getBounds());
+                    }
+                }
+                vectors.addFeatures(features);
+                map.zoomToExtent(bounds);
+                var plural = (features.length > 1) ? 's' : '';
+                element.value = features.length + ' feature' + plural + ' added'
+            } else {
+                element.value = 'Bad GeoJSON';
+            }
+        }
         // -->
     </script>
   </head>
@@ -81,29 +109,36 @@
     <h1>OpenLayers GeoJSON Example</h1>
     <div id="info"></div>
     <div id="map"></div>
-    <ul id="controlToggle">
-        <li>
-            <input type="radio" name="type" value="none" id="noneToggle"
-                   onclick="toggleControl(this);" checked="checked" />
-            <label for="noneToggle">navigate</label>
-        </li>
-        <li>
-            <input type="radio" name="type" value="point" id="pointToggle" onclick="toggleControl(this);" />
-            <label for="pointToggle">draw point</label>
-        </li>
-        <li>
-            <input type="radio" name="type" value="line" id="lineToggle" onclick="toggleControl(this);" />
-            <label for="lineToggle">draw line</label>
-        </li>
-        <li>
-            <input type="radio" name="type" value="polygon" id="polygonToggle" onclick="toggleControl(this);" />
-            <label for="polygonToggle">draw polygon</label>
-        </li>
-        <li>
-            <input type="radio" name="type" value="hover" id="hoverToggle"
-                   onclick="toggleControl(this);" />
-            <label for="hoverToggle">view GeoJSON for feature (on hover)</label>
-        </li>
-    </ul>        
+    <div id="controls">
+        <div id="geoJSONInput">
+            <textarea id="geojson" rows="6" cols="30">paste GeoJSON here...</textarea>
+            <br />
+            <input type="button" value="add feature" onclick="parseGeoJSON();" />
+        </div>
+        <ul id="controlToggle">
+            <li>
+                <input type="radio" name="type" value="none" id="noneToggle"
+                       onclick="toggleControl(this);" checked="checked" />
+                <label for="noneToggle">navigate</label>
+            </li>
+            <li>
+                <input type="radio" name="type" value="point" id="pointToggle" onclick="toggleControl(this);" />
+                <label for="pointToggle">draw point</label>
+            </li>
+            <li>
+                <input type="radio" name="type" value="line" id="lineToggle" onclick="toggleControl(this);" />
+                <label for="lineToggle">draw line</label>
+            </li>
+            <li>
+                <input type="radio" name="type" value="polygon" id="polygonToggle" onclick="toggleControl(this);" />
+                <label for="polygonToggle">draw polygon</label>
+            </li>
+            <li>
+                <input type="radio" name="type" value="hover" id="hoverToggle"
+                       onclick="toggleControl(this);" />
+                <label for="hoverToggle">view GeoJSON feature collection (on hover)</label>
+            </li>
+        </ul>
+    </div>
   </body>
 </html>

Added: sandbox/tschaub/geojson/lib/Firebug/DebugOpenLayers.js
===================================================================
--- sandbox/tschaub/geojson/lib/Firebug/DebugOpenLayers.js	                        (rev 0)
+++ sandbox/tschaub/geojson/lib/Firebug/DebugOpenLayers.js	2007-05-23 22:54:22 UTC (rev 3164)
@@ -0,0 +1,699 @@
+/**
+ * Include this script in your OpenLayers application after the OpenLayers.js
+ * script tag to get Firebug debugging in any browser.  With this script
+ * included, if a browser has the Firebug extension installed, calls to
+ * OpenLayers.console will get rerouted to console.  If a browser does not
+ * have the Firebug extension installed, this script mimics the behavior
+ * of that extension.  With this script included, the Firebug console can
+ * be opened with F12 or Ctrl+Shift+L (or ?+Shift+L on a Mac).
+ *
+ * This script is based on the firebug.js script from
+ * http://www.getfirebug.com/lite.html
+ * Modifications include putting the console object in the OpenLayers
+ * namespace, modifying getFirebugURL, and re-routing OpenLayers.console calls
+ * to console if the Firebug extension is installed.
+ */
+
+
+if (("console" in window) && ("firebug" in console)) {
+    /**
+     * If the Firebug extension is installed, re-route all OpenLayers.console
+     * calls to the console object.
+     */
+    OpenLayers.Util.extend(OpenLayers.console, console);
+} else {
+    /**
+     * An anonymous function is called here so that variables are not
+     * global in scope.
+     */
+    (function()
+    {
+        OpenLayers.console = 
+        {
+            log: function()
+            {
+                logFormatted(arguments, "");
+            },
+            
+            debug: function()
+            {
+                logFormatted(arguments, "debug");
+            },
+            
+            info: function()
+            {
+                logFormatted(arguments, "info");
+            },
+            
+            warn: function()
+            {
+                logFormatted(arguments, "warning");
+            },
+            
+            error: function()
+            {
+                logFormatted(arguments, "error");
+            },
+            
+            assert: function(truth, message)
+            {
+                if (!truth)
+                {
+                    var args = [];
+                    for (var i = 1; i < arguments.length; ++i)
+                        args.push(arguments[i]);
+                    
+                    logFormatted(args.length ? args : ["Assertion Failure"], "error");
+                    throw message ? message : "Assertion Failure";
+                }
+            },
+            
+            dir: function(object)
+            {
+                var html = [];
+                            
+                var pairs = [];
+                for (var name in object)
+                {
+                    try
+                    {
+                        pairs.push([name, object[name]]);
+                    }
+                    catch (exc)
+                    {
+                    }
+                }
+                
+                pairs.sort(function(a, b) { return a[0] < b[0] ? -1 : 1; });
+                
+                html.push('<table>');
+                for (var i = 0; i < pairs.length; ++i)
+                {
+                    var name = pairs[i][0], value = pairs[i][1];
+                    
+                    html.push('<tr>', 
+                    '<td class="propertyNameCell"><span class="propertyName">',
+                        escapeHTML(name), '</span></td>', '<td><span class="propertyValue">');
+                    appendObject(value, html);
+                    html.push('</span></td></tr>');
+                }
+                html.push('</table>');
+                
+                logRow(html, "dir");
+            },
+            
+            dirxml: function(node)
+            {
+                var html = [];
+                
+                appendNode(node, html);
+                logRow(html, "dirxml");
+            },
+            
+            group: function()
+            {
+                logRow(arguments, "group", pushGroup);
+            },
+            
+            groupEnd: function()
+            {
+                logRow(arguments, "", popGroup);
+            },
+            
+            time: function(name)
+            {
+                timeMap[name] = (new Date()).getTime();
+            },
+            
+            timeEnd: function(name)
+            {
+                if (name in timeMap)
+                {
+                    var delta = (new Date()).getTime() - timeMap[name];
+                    logFormatted([name+ ":", delta+"ms"]);
+                    delete timeMap[name];
+                }
+            },
+            
+            count: function()
+            {
+                this.warn(["count() not supported."]);
+            },
+            
+            trace: function()
+            {
+                this.warn(["trace() not supported."]);
+            },
+            
+            profile: function()
+            {
+                this.warn(["profile() not supported."]);
+            },
+            
+            profileEnd: function()
+            {
+            },
+            
+            clear: function()
+            {
+                consoleBody.innerHTML = "";
+            },
+    
+            open: function()
+            {
+                toggleConsole(true);
+            },
+            
+            close: function()
+            {
+                if (frameVisible)
+                    toggleConsole();
+            }
+        };
+     
+        // ********************************************************************************************
+           
+        var consoleFrame = null;
+        var consoleBody = null;
+        var commandLine = null;
+        
+        var frameVisible = false;
+        var messageQueue = [];
+        var groupStack = [];
+        var timeMap = {};
+        
+        var clPrefix = ">>> ";
+        
+        var isFirefox = navigator.userAgent.indexOf("Firefox") != -1;
+        var isIE = navigator.userAgent.indexOf("MSIE") != -1;
+        var isOpera = navigator.userAgent.indexOf("Opera") != -1;
+        var isSafari = navigator.userAgent.indexOf("AppleWebKit") != -1;
+    
+        // ********************************************************************************************
+    
+        function toggleConsole(forceOpen)
+        {
+            frameVisible = forceOpen || !frameVisible;
+            if (consoleFrame)
+                consoleFrame.style.visibility = frameVisible ? "visible" : "hidden";
+            else
+                waitForBody();
+        }
+    
+        function focusCommandLine()
+        {
+            toggleConsole(true);
+            if (commandLine)
+                commandLine.focus();
+        }
+    
+        function waitForBody()
+        {
+            if (document.body)
+                createFrame();
+            else
+                setTimeout(waitForBody, 200);
+        }    
+    
+        function createFrame()
+        {
+            if (consoleFrame)
+                return;
+            
+            window.onFirebugReady = function(doc)
+            {
+                window.onFirebugReady = null;
+    
+                var toolbar = doc.getElementById("toolbar");
+                toolbar.onmousedown = onSplitterMouseDown;
+    
+                commandLine = doc.getElementById("commandLine");
+                addEvent(commandLine, "keydown", onCommandLineKeyDown);
+    
+                addEvent(doc, isIE || isSafari ? "keydown" : "keypress", onKeyDown);
+                
+                consoleBody = doc.getElementById("log");
+                layout();
+                flush();
+            }
+    
+            var baseURL = getFirebugURL();
+    
+            consoleFrame = document.createElement("iframe");
+            consoleFrame.setAttribute("src", baseURL+"/firebug.html");
+            consoleFrame.setAttribute("frameBorder", "0");
+            consoleFrame.style.visibility = (frameVisible ? "visible" : "hidden");    
+            consoleFrame.style.zIndex = "2147483647";
+            consoleFrame.style.position = "fixed";
+            consoleFrame.style.width = "100%";
+            consoleFrame.style.left = "0";
+            consoleFrame.style.bottom = "0";
+            consoleFrame.style.height = "200px";
+            document.body.appendChild(consoleFrame);
+        }
+        
+        function getFirebugURL()
+        {
+            var scripts = document.getElementsByTagName("script");
+            for (var i = 0; i < scripts.length; ++i)
+            {
+                if (scripts[i].src.indexOf("DebugOpenLayers.js") != -1)
+                {
+                    var lastSlash = scripts[i].src.lastIndexOf("/");
+                    return scripts[i].src.substr(0, lastSlash);
+                }
+            }
+        }
+        
+        function evalCommandLine()
+        {
+            var text = commandLine.value;
+            commandLine.value = "";
+    
+            logRow([clPrefix, text], "command");
+            
+            var value;
+            try
+            {
+                value = eval(text);
+            }
+            catch (exc)
+            {
+            }
+    
+            OpenLayers.console.log(value);
+        }
+        
+        function layout()
+        {
+            var toolbar = consoleBody.ownerDocument.getElementById("toolbar");
+            var height = consoleFrame.offsetHeight - (toolbar.offsetHeight + commandLine.offsetHeight);
+            height = Math.max(height, 0);
+            consoleBody.style.top = toolbar.offsetHeight + "px";
+            consoleBody.style.height = height + "px";
+            commandLine.style.top = (consoleFrame.offsetHeight - commandLine.offsetHeight) + "px";
+        }
+        
+        function logRow(message, className, handler)
+        {
+            if (consoleBody)
+                writeMessage(message, className, handler);
+            else
+            {
+                messageQueue.push([message, className, handler]);
+                waitForBody();
+            }
+        }
+        
+        function flush()
+        {
+            var queue = messageQueue;
+            messageQueue = [];
+            
+            for (var i = 0; i < queue.length; ++i)
+                writeMessage(queue[i][0], queue[i][1], queue[i][2]);
+        }
+    
+        function writeMessage(message, className, handler)
+        {
+            var isScrolledToBottom =
+                consoleBody.scrollTop + consoleBody.offsetHeight >= consoleBody.scrollHeight;
+    
+            if (!handler)
+                handler = writeRow;
+            
+            handler(message, className);
+            
+            if (isScrolledToBottom)
+                consoleBody.scrollTop = consoleBody.scrollHeight - consoleBody.offsetHeight;
+        }
+        
+        function appendRow(row)
+        {
+            var container = groupStack.length ? groupStack[groupStack.length-1] : consoleBody;
+            container.appendChild(row);
+        }
+    
+        function writeRow(message, className)
+        {
+            var row = consoleBody.ownerDocument.createElement("div");
+            row.className = "logRow" + (className ? " logRow-"+className : "");
+            row.innerHTML = message.join("");
+            appendRow(row);
+        }
+    
+        function pushGroup(message, className)
+        {
+            logFormatted(message, className);
+    
+            var groupRow = consoleBody.ownerDocument.createElement("div");
+            groupRow.className = "logGroup";
+            var groupRowBox = consoleBody.ownerDocument.createElement("div");
+            groupRowBox.className = "logGroupBox";
+            groupRow.appendChild(groupRowBox);
+            appendRow(groupRowBox);
+            groupStack.push(groupRowBox);
+        }
+    
+        function popGroup()
+        {
+            groupStack.pop();
+        }
+        
+        // ********************************************************************************************
+    
+        function logFormatted(objects, className)
+        {
+            var html = [];
+    
+            var format = objects[0];
+            var objIndex = 0;
+    
+            if (typeof(format) != "string")
+            {
+                format = "";
+                objIndex = -1;
+            }
+    
+            var parts = parseFormat(format);
+            for (var i = 0; i < parts.length; ++i)
+            {
+                var part = parts[i];
+                if (part && typeof(part) == "object")
+                {
+                    var object = objects[++objIndex];
+                    part.appender(object, html);
+                }
+                else
+                    appendText(part, html);
+            }
+    
+            for (var i = objIndex+1; i < objects.length; ++i)
+            {
+                appendText(" ", html);
+                
+                var object = objects[i];
+                if (typeof(object) == "string")
+                    appendText(object, html);
+                else
+                    appendObject(object, html);
+            }
+            
+            logRow(html, className);
+        }
+    
+        function parseFormat(format)
+        {
+            var parts = [];
+    
+            var reg = /((^%|[^\\]%)(\d+)?(\.)([a-zA-Z]))|((^%|[^\\]%)([a-zA-Z]))/;    
+            var appenderMap = {s: appendText, d: appendInteger, i: appendInteger, f: appendFloat};
+    
+            for (var m = reg.exec(format); m; m = reg.exec(format))
+            {
+                var type = m[8] ? m[8] : m[5];
+                var appender = type in appenderMap ? appenderMap[type] : appendObject;
+                var precision = m[3] ? parseInt(m[3]) : (m[4] == "." ? -1 : 0);
+    
+                parts.push(format.substr(0, m[0][0] == "%" ? m.index : m.index+1));
+                parts.push({appender: appender, precision: precision});
+    
+                format = format.substr(m.index+m[0].length);
+            }
+    
+            parts.push(format);
+    
+            return parts;
+        }
+    
+        function escapeHTML(value)
+        {
+            function replaceChars(ch)
+            {
+                switch (ch)
+                {
+                    case "<":
+                        return "&lt;";
+                    case ">":
+                        return "&gt;";
+                    case "&":
+                        return "&amp;";
+                    case "'":
+                        return "&#39;";
+                    case '"':
+                        return "&quot;";
+                }
+                return "?";
+            };
+            return String(value).replace(/[<>&"']/g, replaceChars);
+        }
+    
+        function objectToString(object)
+        {
+            try
+            {
+                return object+"";
+            }
+            catch (exc)
+            {
+                return null;
+            }
+        }
+    
+        // ********************************************************************************************
+    
+        function appendText(object, html)
+        {
+            html.push(escapeHTML(objectToString(object)));
+        }
+    
+        function appendNull(object, html)
+        {
+            html.push('<span class="objectBox-null">', escapeHTML(objectToString(object)), '</span>');
+        }
+    
+        function appendString(object, html)
+        {
+            html.push('<span class="objectBox-string">&quot;', escapeHTML(objectToString(object)),
+                '&quot;</span>');
+        }
+    
+        function appendInteger(object, html)
+        {
+            html.push('<span class="objectBox-number">', escapeHTML(objectToString(object)), '</span>');
+        }
+    
+        function appendFloat(object, html)
+        {
+            html.push('<span class="objectBox-number">', escapeHTML(objectToString(object)), '</span>');
+        }
+    
+        function appendFunction(object, html)
+        {
+            var reName = /function ?(.*?)\(/;
+            var m = reName.exec(objectToString(object));
+            var name = m ? m[1] : "function";
+            html.push('<span class="objectBox-function">', escapeHTML(name), '()</span>');
+        }
+        
+        function appendObject(object, html)
+        {
+            try
+            {
+                if (object == undefined)
+                    appendNull("undefined", html);
+                else if (object == null)
+                    appendNull("null", html);
+                else if (typeof object == "string")
+                    appendString(object, html);
+                else if (typeof object == "number")
+                    appendInteger(object, html);
+                else if (typeof object == "function")
+                    appendFunction(object, html);
+                else if (object.nodeType == 1)
+                    appendSelector(object, html);
+                else if (typeof object == "object")
+                    appendObjectFormatted(object, html);
+                else
+                    appendText(object, html);
+            }
+            catch (exc)
+            {
+            }
+        }
+            
+        function appendObjectFormatted(object, html)
+        {
+            var text = objectToString(object);
+            var reObject = /\[object (.*?)\]/;
+    
+            var m = reObject.exec(text);
+            html.push('<span class="objectBox-object">', m ? m[1] : text, '</span>')
+        }
+        
+        function appendSelector(object, html)
+        {
+            html.push('<span class="objectBox-selector">');
+    
+            html.push('<span class="selectorTag">', escapeHTML(object.nodeName.toLowerCase()), '</span>');
+            if (object.id)
+                html.push('<span class="selectorId">#', escapeHTML(object.id), '</span>');
+            if (object.className)
+                html.push('<span class="selectorClass">.', escapeHTML(object.className), '</span>');
+    
+            html.push('</span>');
+        }
+    
+        function appendNode(node, html)
+        {
+            if (node.nodeType == 1)
+            {
+                html.push(
+                    '<div class="objectBox-element">',
+                        '&lt;<span class="nodeTag">', node.nodeName.toLowerCase(), '</span>');
+    
+                for (var i = 0; i < node.attributes.length; ++i)
+                {
+                    var attr = node.attributes[i];
+                    if (!attr.specified)
+                        continue;
+                    
+                    html.push('&nbsp;<span class="nodeName">', attr.nodeName.toLowerCase(),
+                        '</span>=&quot;<span class="nodeValue">', escapeHTML(attr.nodeValue),
+                        '</span>&quot;')
+                }
+    
+                if (node.firstChild)
+                {
+                    html.push('&gt;</div><div class="nodeChildren">');
+    
+                    for (var child = node.firstChild; child; child = child.nextSibling)
+                        appendNode(child, html);
+                        
+                    html.push('</div><div class="objectBox-element">&lt;/<span class="nodeTag">', 
+                        node.nodeName.toLowerCase(), '&gt;</span></div>');
+                }
+                else
+                    html.push('/&gt;</div>');
+            }
+            else if (node.nodeType == 3)
+            {
+                html.push('<div class="nodeText">', escapeHTML(node.nodeValue),
+                    '</div>');
+            }
+        }
+    
+        // ********************************************************************************************
+        
+        function addEvent(object, name, handler)
+        {
+            if (document.all)
+                object.attachEvent("on"+name, handler);
+            else
+                object.addEventListener(name, handler, false);
+        }
+        
+        function removeEvent(object, name, handler)
+        {
+            if (document.all)
+                object.detachEvent("on"+name, handler);
+            else
+                object.removeEventListener(name, handler, false);
+        }
+        
+        function cancelEvent(event)
+        {
+            if (document.all)
+                event.cancelBubble = true;
+            else
+                event.stopPropagation();        
+        }
+    
+        function onError(msg, href, lineNo)
+        {
+            var html = [];
+            
+            var lastSlash = href.lastIndexOf("/");
+            var fileName = lastSlash == -1 ? href : href.substr(lastSlash+1);
+            
+            html.push(
+                '<span class="errorMessage">', msg, '</span>', 
+                '<div class="objectBox-sourceLink">', fileName, ' (line ', lineNo, ')</div>'
+            );
+            
+            logRow(html, "error");
+        };
+    
+        function onKeyDown(event)
+        {
+            if (event.keyCode == 123)
+                toggleConsole();
+            else if ((event.keyCode == 108 || event.keyCode == 76) && event.shiftKey
+                     && (event.metaKey || event.ctrlKey))
+                focusCommandLine();
+            else
+                return;
+            
+            cancelEvent(event);
+        }
+    
+        function onSplitterMouseDown(event)
+        {
+            if (isSafari || isOpera)
+                return;
+            
+            addEvent(document, "mousemove", onSplitterMouseMove);
+            addEvent(document, "mouseup", onSplitterMouseUp);
+    
+            for (var i = 0; i < frames.length; ++i)
+            {
+                addEvent(frames[i].document, "mousemove", onSplitterMouseMove);
+                addEvent(frames[i].document, "mouseup", onSplitterMouseUp);
+            }
+        }
+        
+        function onSplitterMouseMove(event)
+        {
+            var win = document.all
+                ? event.srcElement.ownerDocument.parentWindow
+                : event.target.ownerDocument.defaultView;
+    
+            var clientY = event.clientY;
+            if (win != win.parent)
+                clientY += win.frameElement ? win.frameElement.offsetTop : 0;
+            
+            var height = consoleFrame.offsetTop + consoleFrame.clientHeight;
+            var toolbar = consoleBody.ownerDocument.getElementById("toolbar");
+            var y = Math.max(height - clientY,
+                             toolbar.offsetHeight + commandLine.offsetHeight);
+            consoleFrame.style.height = y + "px";
+            layout();
+        }
+        
+        function onSplitterMouseUp(event)
+        {
+            removeEvent(document, "mousemove", onSplitterMouseMove);
+            removeEvent(document, "mouseup", onSplitterMouseUp);
+    
+            for (var i = 0; i < frames.length; ++i)
+            {
+                removeEvent(frames[i].document, "mousemove", onSplitterMouseMove);
+                removeEvent(frames[i].document, "mouseup", onSplitterMouseUp);
+            }
+        }
+        
+        function onCommandLineKeyDown(event)
+        {
+            if (event.keyCode == 13)
+                evalCommandLine();
+            else if (event.keyCode == 27)
+                commandLine.value = "";
+        }
+        
+        window.onerror = onError;
+        addEvent(document, isIE || isSafari ? "keydown" : "keypress", onKeyDown);
+        
+        if (document.documentElement.getAttribute("debug") == "true")
+            toggleConsole(true);
+    })();
+}

Added: sandbox/tschaub/geojson/lib/Firebug/errorIcon.png
===================================================================
(Binary files differ)


Property changes on: sandbox/tschaub/geojson/lib/Firebug/errorIcon.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: sandbox/tschaub/geojson/lib/Firebug/firebug.css
===================================================================
--- sandbox/tschaub/geojson/lib/Firebug/firebug.css	                        (rev 0)
+++ sandbox/tschaub/geojson/lib/Firebug/firebug.css	2007-05-23 22:54:22 UTC (rev 3164)
@@ -0,0 +1,209 @@
+
+html, body {
+    margin: 0;
+    background: #FFFFFF;
+    font-family: Lucida Grande, Tahoma, sans-serif;
+    font-size: 11px;
+    overflow: hidden;
+}
+
+a {
+    text-decoration: none;
+}
+
+a:hover {
+    text-decoration: underline;
+}
+
+.toolbar {
+    height: 14px;
+    border-top: 1px solid ThreeDHighlight;
+    border-bottom: 1px solid ThreeDShadow;
+    padding: 2px 6px;
+    background: ThreeDFace;
+}
+
+.toolbarRight {
+    position: absolute;
+    top: 4px;
+    right: 6px;
+}
+
+#log {
+    overflow: auto;
+    position: absolute;
+    left: 0;
+    width: 100%;
+}
+
+#commandLine {
+    position: absolute;
+    bottom: 0;
+    left: 0;
+    width: 100%;
+    height: 18px;
+    border: none;
+    border-top: 1px solid ThreeDShadow;
+}
+
+/************************************************************************************************/
+
+.logRow {
+    position: relative;
+    border-bottom: 1px solid #D7D7D7;
+    padding: 2px 4px 1px 6px;
+    background-color: #FFFFFF;
+}
+
+.logRow-command {
+    font-family: Monaco, monospace;
+    color: blue;
+}
+
+.objectBox-null {
+    padding: 0 2px;
+    border: 1px solid #666666;
+    background-color: #888888;
+    color: #FFFFFF;
+}
+
+.objectBox-string {
+    font-family: Monaco, monospace;
+    color: red;
+    white-space: pre;
+}
+
+.objectBox-number {
+    color: #000088;
+}
+
+.objectBox-function {
+    font-family: Monaco, monospace;
+    color: DarkGreen;
+}
+
+.objectBox-object {
+    color: DarkGreen;
+    font-weight: bold;
+}
+
+/************************************************************************************************/
+
+.logRow-info,
+.logRow-error,
+.logRow-warning {
+    background: #FFFFFF no-repeat 2px 2px;
+    padding-left: 20px;
+    padding-bottom: 3px;
+}
+
+.logRow-info {
+    background-image: url(infoIcon.png);
+}
+
+.logRow-warning {
+    background-color: cyan;
+    background-image: url(warningIcon.png);
+}
+
+.logRow-error {
+    background-color: LightYellow;
+    background-image: url(errorIcon.png);
+}
+
+.errorMessage {
+    vertical-align: top;
+    color: #FF0000;
+}
+
+.objectBox-sourceLink {
+    position: absolute;
+    right: 4px;
+    top: 2px;
+    padding-left: 8px;
+    font-family: Lucida Grande, sans-serif;
+    font-weight: bold;
+    color: #0000FF;
+}
+
+/************************************************************************************************/
+
+.logRow-group {
+    background: #EEEEEE;
+    border-bottom: none;
+}
+
+.logGroup {
+    background: #EEEEEE;
+}
+
+.logGroupBox {
+    margin-left: 24px;
+    border-top: 1px solid #D7D7D7;
+    border-left: 1px solid #D7D7D7;
+}
+
+/************************************************************************************************/
+
+.selectorTag,
+.selectorId,
+.selectorClass {
+    font-family: Monaco, monospace;
+    font-weight: normal;
+}
+
+.selectorTag {
+    color: #0000FF;
+}
+
+.selectorId {
+    color: DarkBlue;
+}
+
+.selectorClass {
+    color: red;
+}
+
+/************************************************************************************************/
+
+.objectBox-element {
+    font-family: Monaco, monospace;
+    color: #000088;
+}
+
+.nodeChildren {
+    margin-left: 16px;
+}
+
+.nodeTag {
+    color: blue;
+}
+
+.nodeValue {
+    color: #FF0000;
+    font-weight: normal;
+}
+
+.nodeText,
+.nodeComment {
+    margin: 0 2px;
+    vertical-align: top;
+}
+
+.nodeText {
+    color: #333333;
+}
+
+.nodeComment {
+    color: DarkGreen;
+}
+
+/************************************************************************************************/
+
+.propertyNameCell {
+    vertical-align: top;
+}
+
+.propertyName {
+    font-weight: bold;
+}

Added: sandbox/tschaub/geojson/lib/Firebug/firebug.html
===================================================================
--- sandbox/tschaub/geojson/lib/Firebug/firebug.html	                        (rev 0)
+++ sandbox/tschaub/geojson/lib/Firebug/firebug.html	2007-05-23 22:54:22 UTC (rev 3164)
@@ -0,0 +1,23 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+         "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+
+<head>
+    <title>Firebug</title>
+    <link rel="stylesheet" type="text/css" href="firebug.css">
+</head>
+
+<body>
+    <div id="toolbar" class="toolbar">
+        <a href="#" onclick="parent.OpenLayers.console.clear()">Clear</a>
+        <span class="toolbarRight">
+            <a href="#" onclick="parent.OpenLayers.console.close()">Close</a>
+        </span>
+    </div>
+    <div id="log"></div>
+    <input type="text" id="commandLine">
+    
+    <script>parent.onFirebugReady(document);</script>
+</body>
+</html>

Added: sandbox/tschaub/geojson/lib/Firebug/firebug.js
===================================================================
--- sandbox/tschaub/geojson/lib/Firebug/firebug.js	                        (rev 0)
+++ sandbox/tschaub/geojson/lib/Firebug/firebug.js	2007-05-23 22:54:22 UTC (rev 3164)
@@ -0,0 +1,672 @@
+
+if (!("console" in window) || !("firebug" in console)) {
+(function()
+{
+    window.console = 
+    {
+        log: function()
+        {
+            logFormatted(arguments, "");
+        },
+        
+        debug: function()
+        {
+            logFormatted(arguments, "debug");
+        },
+        
+        info: function()
+        {
+            logFormatted(arguments, "info");
+        },
+        
+        warn: function()
+        {
+            logFormatted(arguments, "warning");
+        },
+        
+        error: function()
+        {
+            logFormatted(arguments, "error");
+        },
+        
+        assert: function(truth, message)
+        {
+            if (!truth)
+            {
+                var args = [];
+                for (var i = 1; i < arguments.length; ++i)
+                    args.push(arguments[i]);
+                
+                logFormatted(args.length ? args : ["Assertion Failure"], "error");
+                throw message ? message : "Assertion Failure";
+            }
+        },
+        
+        dir: function(object)
+        {
+            var html = [];
+                        
+            var pairs = [];
+            for (var name in object)
+            {
+                try
+                {
+                    pairs.push([name, object[name]]);
+                }
+                catch (exc)
+                {
+                }
+            }
+            
+            pairs.sort(function(a, b) { return a[0] < b[0] ? -1 : 1; });
+            
+            html.push('<table>');
+            for (var i = 0; i < pairs.length; ++i)
+            {
+                var name = pairs[i][0], value = pairs[i][1];
+                
+                html.push('<tr>', 
+                '<td class="propertyNameCell"><span class="propertyName">',
+                    escapeHTML(name), '</span></td>', '<td><span class="propertyValue">');
+                appendObject(value, html);
+                html.push('</span></td></tr>');
+            }
+            html.push('</table>');
+            
+            logRow(html, "dir");
+        },
+        
+        dirxml: function(node)
+        {
+            var html = [];
+            
+            appendNode(node, html);
+            logRow(html, "dirxml");
+        },
+        
+        group: function()
+        {
+            logRow(arguments, "group", pushGroup);
+        },
+        
+        groupEnd: function()
+        {
+            logRow(arguments, "", popGroup);
+        },
+        
+        time: function(name)
+        {
+            timeMap[name] = (new Date()).getTime();
+        },
+        
+        timeEnd: function(name)
+        {
+            if (name in timeMap)
+            {
+                var delta = (new Date()).getTime() - timeMap[name];
+                logFormatted([name+ ":", delta+"ms"]);
+                delete timeMap[name];
+            }
+        },
+        
+        count: function()
+        {
+            this.warn(["count() not supported."]);
+        },
+        
+        trace: function()
+        {
+            this.warn(["trace() not supported."]);
+        },
+        
+        profile: function()
+        {
+            this.warn(["profile() not supported."]);
+        },
+        
+        profileEnd: function()
+        {
+        },
+        
+        clear: function()
+        {
+            consoleBody.innerHTML = "";
+        },
+
+        open: function()
+        {
+            toggleConsole(true);
+        },
+        
+        close: function()
+        {
+            if (frameVisible)
+                toggleConsole();
+        }
+    };
+ 
+    // ********************************************************************************************
+       
+    var consoleFrame = null;
+    var consoleBody = null;
+    var commandLine = null;
+    
+    var frameVisible = false;
+    var messageQueue = [];
+    var groupStack = [];
+    var timeMap = {};
+    
+    var clPrefix = ">>> ";
+    
+    var isFirefox = navigator.userAgent.indexOf("Firefox") != -1;
+    var isIE = navigator.userAgent.indexOf("MSIE") != -1;
+    var isOpera = navigator.userAgent.indexOf("Opera") != -1;
+    var isSafari = navigator.userAgent.indexOf("AppleWebKit") != -1;
+
+    // ********************************************************************************************
+
+    function toggleConsole(forceOpen)
+    {
+        frameVisible = forceOpen || !frameVisible;
+        if (consoleFrame)
+            consoleFrame.style.visibility = frameVisible ? "visible" : "hidden";
+        else
+            waitForBody();
+    }
+
+    function focusCommandLine()
+    {
+        toggleConsole(true);
+        if (commandLine)
+            commandLine.focus();
+    }
+
+    function waitForBody()
+    {
+        if (document.body)
+            createFrame();
+        else
+            setTimeout(waitForBody, 200);
+    }    
+
+    function createFrame()
+    {
+        if (consoleFrame)
+            return;
+        
+        window.onFirebugReady = function(doc)
+        {
+            window.onFirebugReady = null;
+
+            var toolbar = doc.getElementById("toolbar");
+            toolbar.onmousedown = onSplitterMouseDown;
+
+            commandLine = doc.getElementById("commandLine");
+            addEvent(commandLine, "keydown", onCommandLineKeyDown);
+
+            addEvent(doc, isIE || isSafari ? "keydown" : "keypress", onKeyDown);
+            
+            consoleBody = doc.getElementById("log");
+            layout();
+            flush();
+        }
+
+        var baseURL = getFirebugURL();
+
+        consoleFrame = document.createElement("iframe");
+        consoleFrame.setAttribute("src", baseURL+"/firebug.html");
+        consoleFrame.setAttribute("frameBorder", "0");
+        consoleFrame.style.visibility = (frameVisible ? "visible" : "hidden");    
+        consoleFrame.style.zIndex = "2147483647";
+        consoleFrame.style.position = "fixed";
+        consoleFrame.style.width = "100%";
+        consoleFrame.style.left = "0";
+        consoleFrame.style.bottom = "0";
+        consoleFrame.style.height = "200px";
+        document.body.appendChild(consoleFrame);
+    }
+    
+    function getFirebugURL()
+    {
+        var scripts = document.getElementsByTagName("script");
+        for (var i = 0; i < scripts.length; ++i)
+        {
+            if (scripts[i].src.indexOf("firebug.js") != -1)
+            {
+                var lastSlash = scripts[i].src.lastIndexOf("/");
+                return scripts[i].src.substr(0, lastSlash);
+            }
+        }
+    }
+    
+    function evalCommandLine()
+    {
+        var text = commandLine.value;
+        commandLine.value = "";
+
+        logRow([clPrefix, text], "command");
+        
+        var value;
+        try
+        {
+            value = eval(text);
+        }
+        catch (exc)
+        {
+        }
+
+        console.log(value);
+    }
+    
+    function layout()
+    {
+        var toolbar = consoleBody.ownerDocument.getElementById("toolbar");
+        var height = consoleFrame.offsetHeight - (toolbar.offsetHeight + commandLine.offsetHeight);
+        consoleBody.style.top = toolbar.offsetHeight + "px";
+        consoleBody.style.height = height + "px";
+        
+        commandLine.style.top = (consoleFrame.offsetHeight - commandLine.offsetHeight) + "px";
+    }
+    
+    function logRow(message, className, handler)
+    {
+        if (consoleBody)
+            writeMessage(message, className, handler);
+        else
+        {
+            messageQueue.push([message, className, handler]);
+            waitForBody();
+        }
+    }
+    
+    function flush()
+    {
+        var queue = messageQueue;
+        messageQueue = [];
+        
+        for (var i = 0; i < queue.length; ++i)
+            writeMessage(queue[i][0], queue[i][1], queue[i][2]);
+    }
+
+    function writeMessage(message, className, handler)
+    {
+        var isScrolledToBottom =
+            consoleBody.scrollTop + consoleBody.offsetHeight >= consoleBody.scrollHeight;
+
+        if (!handler)
+            handler = writeRow;
+        
+        handler(message, className);
+        
+        if (isScrolledToBottom)
+            consoleBody.scrollTop = consoleBody.scrollHeight - consoleBody.offsetHeight;
+    }
+    
+    function appendRow(row)
+    {
+        var container = groupStack.length ? groupStack[groupStack.length-1] : consoleBody;
+        container.appendChild(row);
+    }
+
+    function writeRow(message, className)
+    {
+        var row = consoleBody.ownerDocument.createElement("div");
+        row.className = "logRow" + (className ? " logRow-"+className : "");
+        row.innerHTML = message.join("");
+        appendRow(row);
+    }
+
+    function pushGroup(message, className)
+    {
+        logFormatted(message, className);
+
+        var groupRow = consoleBody.ownerDocument.createElement("div");
+        groupRow.className = "logGroup";
+        var groupRowBox = consoleBody.ownerDocument.createElement("div");
+        groupRowBox.className = "logGroupBox";
+        groupRow.appendChild(groupRowBox);
+        appendRow(groupRowBox);
+        groupStack.push(groupRowBox);
+    }
+
+    function popGroup()
+    {
+        groupStack.pop();
+    }
+    
+    // ********************************************************************************************
+
+    function logFormatted(objects, className)
+    {
+        var html = [];
+
+        var format = objects[0];
+        var objIndex = 0;
+
+        if (typeof(format) != "string")
+        {
+            format = "";
+            objIndex = -1;
+        }
+
+        var parts = parseFormat(format);
+        for (var i = 0; i < parts.length; ++i)
+        {
+            var part = parts[i];
+            if (part && typeof(part) == "object")
+            {
+                var object = objects[++objIndex];
+                part.appender(object, html);
+            }
+            else
+                appendText(part, html);
+        }
+
+        for (var i = objIndex+1; i < objects.length; ++i)
+        {
+            appendText(" ", html);
+            
+            var object = objects[i];
+            if (typeof(object) == "string")
+                appendText(object, html);
+            else
+                appendObject(object, html);
+        }
+        
+        logRow(html, className);
+    }
+
+    function parseFormat(format)
+    {
+        var parts = [];
+
+        var reg = /((^%|[^\\]%)(\d+)?(\.)([a-zA-Z]))|((^%|[^\\]%)([a-zA-Z]))/;    
+        var appenderMap = {s: appendText, d: appendInteger, i: appendInteger, f: appendFloat};
+
+        for (var m = reg.exec(format); m; m = reg.exec(format))
+        {
+            var type = m[8] ? m[8] : m[5];
+            var appender = type in appenderMap ? appenderMap[type] : appendObject;
+            var precision = m[3] ? parseInt(m[3]) : (m[4] == "." ? -1 : 0);
+
+            parts.push(format.substr(0, m[0][0] == "%" ? m.index : m.index+1));
+            parts.push({appender: appender, precision: precision});
+
+            format = format.substr(m.index+m[0].length);
+        }
+
+        parts.push(format);
+
+        return parts;
+    }
+
+    function escapeHTML(value)
+    {
+        function replaceChars(ch)
+        {
+            switch (ch)
+            {
+                case "<":
+                    return "&lt;";
+                case ">":
+                    return "&gt;";
+                case "&":
+                    return "&amp;";
+                case "'":
+                    return "&#39;";
+                case '"':
+                    return "&quot;";
+            }
+            return "?";
+        };
+        return String(value).replace(/[<>&"']/g, replaceChars);
+    }
+
+    function objectToString(object)
+    {
+        try
+        {
+            return object+"";
+        }
+        catch (exc)
+        {
+            return null;
+        }
+    }
+
+    // ********************************************************************************************
+
+    function appendText(object, html)
+    {
+        html.push(escapeHTML(objectToString(object)));
+    }
+
+    function appendNull(object, html)
+    {
+        html.push('<span class="objectBox-null">', escapeHTML(objectToString(object)), '</span>');
+    }
+
+    function appendString(object, html)
+    {
+        html.push('<span class="objectBox-string">&quot;', escapeHTML(objectToString(object)),
+            '&quot;</span>');
+    }
+
+    function appendInteger(object, html)
+    {
+        html.push('<span class="objectBox-number">', escapeHTML(objectToString(object)), '</span>');
+    }
+
+    function appendFloat(object, html)
+    {
+        html.push('<span class="objectBox-number">', escapeHTML(objectToString(object)), '</span>');
+    }
+
+    function appendFunction(object, html)
+    {
+        var reName = /function ?(.*?)\(/;
+        var m = reName.exec(objectToString(object));
+        var name = m ? m[1] : "function";
+        html.push('<span class="objectBox-function">', escapeHTML(name), '()</span>');
+    }
+    
+    function appendObject(object, html)
+    {
+        try
+        {
+            if (object == undefined)
+                appendNull("undefined", html);
+            else if (object == null)
+                appendNull("null", html);
+            else if (typeof object == "string")
+                appendString(object, html);
+            else if (typeof object == "number")
+                appendInteger(object, html);
+            else if (typeof object == "function")
+                appendFunction(object, html);
+            else if (object.nodeType == 1)
+                appendSelector(object, html);
+            else if (typeof object == "object")
+                appendObjectFormatted(object, html);
+            else
+                appendText(object, html);
+        }
+        catch (exc)
+        {
+        }
+    }
+        
+    function appendObjectFormatted(object, html)
+    {
+        var text = objectToString(object);
+        var reObject = /\[object (.*?)\]/;
+
+        var m = reObject.exec(text);
+        html.push('<span class="objectBox-object">', m ? m[1] : text, '</span>')
+    }
+    
+    function appendSelector(object, html)
+    {
+        html.push('<span class="objectBox-selector">');
+
+        html.push('<span class="selectorTag">', escapeHTML(object.nodeName.toLowerCase()), '</span>');
+        if (object.id)
+            html.push('<span class="selectorId">#', escapeHTML(object.id), '</span>');
+        if (object.className)
+            html.push('<span class="selectorClass">.', escapeHTML(object.className), '</span>');
+
+        html.push('</span>');
+    }
+
+    function appendNode(node, html)
+    {
+        if (node.nodeType == 1)
+        {
+            html.push(
+                '<div class="objectBox-element">',
+                    '&lt;<span class="nodeTag">', node.nodeName.toLowerCase(), '</span>');
+
+            for (var i = 0; i < node.attributes.length; ++i)
+            {
+                var attr = node.attributes[i];
+                if (!attr.specified)
+                    continue;
+                
+                html.push('&nbsp;<span class="nodeName">', attr.nodeName.toLowerCase(),
+                    '</span>=&quot;<span class="nodeValue">', escapeHTML(attr.nodeValue),
+                    '</span>&quot;')
+            }
+
+            if (node.firstChild)
+            {
+                html.push('&gt;</div><div class="nodeChildren">');
+
+                for (var child = node.firstChild; child; child = child.nextSibling)
+                    appendNode(child, html);
+                    
+                html.push('</div><div class="objectBox-element">&lt;/<span class="nodeTag">', 
+                    node.nodeName.toLowerCase(), '&gt;</span></div>');
+            }
+            else
+                html.push('/&gt;</div>');
+        }
+        else if (node.nodeType == 3)
+        {
+            html.push('<div class="nodeText">', escapeHTML(node.nodeValue),
+                '</div>');
+        }
+    }
+
+    // ********************************************************************************************
+    
+    function addEvent(object, name, handler)
+    {
+        if (document.all)
+            object.attachEvent("on"+name, handler);
+        else
+            object.addEventListener(name, handler, false);
+    }
+    
+    function removeEvent(object, name, handler)
+    {
+        if (document.all)
+            object.detachEvent("on"+name, handler);
+        else
+            object.removeEventListener(name, handler, false);
+    }
+    
+    function cancelEvent(event)
+    {
+        if (document.all)
+            event.cancelBubble = true;
+        else
+            event.stopPropagation();        
+    }
+
+    function onError(msg, href, lineNo)
+    {
+        var html = [];
+        
+        var lastSlash = href.lastIndexOf("/");
+        var fileName = lastSlash == -1 ? href : href.substr(lastSlash+1);
+        
+        html.push(
+            '<span class="errorMessage">', msg, '</span>', 
+            '<div class="objectBox-sourceLink">', fileName, ' (line ', lineNo, ')</div>'
+        );
+        
+        logRow(html, "error");
+    };
+
+    function onKeyDown(event)
+    {
+        if (event.keyCode == 123)
+            toggleConsole();
+        else if ((event.keyCode == 108 || event.keyCode == 76) && event.shiftKey
+                 && (event.metaKey || event.ctrlKey))
+            focusCommandLine();
+        else
+            return;
+        
+        cancelEvent(event);
+    }
+
+    function onSplitterMouseDown(event)
+    {
+        if (isSafari || isOpera)
+            return;
+        
+        addEvent(document, "mousemove", onSplitterMouseMove);
+        addEvent(document, "mouseup", onSplitterMouseUp);
+
+        for (var i = 0; i < frames.length; ++i)
+        {
+            addEvent(frames[i].document, "mousemove", onSplitterMouseMove);
+            addEvent(frames[i].document, "mouseup", onSplitterMouseUp);
+        }
+    }
+    
+    function onSplitterMouseMove(event)
+    {
+        var win = document.all
+            ? event.srcElement.ownerDocument.parentWindow
+            : event.target.ownerDocument.defaultView;
+
+        var clientY = event.clientY;
+        if (win != win.parent)
+            clientY += win.frameElement ? win.frameElement.offsetTop : 0;
+        
+        var height = consoleFrame.offsetTop + consoleFrame.clientHeight;
+        var y = height - clientY;
+        
+        consoleFrame.style.height = y + "px";
+        layout();
+    }
+    
+    function onSplitterMouseUp(event)
+    {
+        removeEvent(document, "mousemove", onSplitterMouseMove);
+        removeEvent(document, "mouseup", onSplitterMouseUp);
+
+        for (var i = 0; i < frames.length; ++i)
+        {
+            removeEvent(frames[i].document, "mousemove", onSplitterMouseMove);
+            removeEvent(frames[i].document, "mouseup", onSplitterMouseUp);
+        }
+    }
+    
+    function onCommandLineKeyDown(event)
+    {
+        if (event.keyCode == 13)
+            evalCommandLine();
+        else if (event.keyCode == 27)
+            commandLine.value = "";
+    }
+    
+    window.onerror = onError;
+    addEvent(document, isIE || isSafari ? "keydown" : "keypress", onKeyDown);
+    
+    if (document.documentElement.getAttribute("debug") == "true")
+        toggleConsole(true);
+})();
+}

Added: sandbox/tschaub/geojson/lib/Firebug/firebugx.js
===================================================================
--- sandbox/tschaub/geojson/lib/Firebug/firebugx.js	                        (rev 0)
+++ sandbox/tschaub/geojson/lib/Firebug/firebugx.js	2007-05-23 22:54:22 UTC (rev 3164)
@@ -0,0 +1,10 @@
+
+if (!("console" in window) || !("firebug" in console))
+{
+    var names = ["log", "debug", "info", "warn", "error", "assert", "dir", "dirxml",
+    "group", "groupEnd", "time", "timeEnd", "count", "trace", "profile", "profileEnd"];
+
+    window.console = {};
+    for (var i = 0; i < names.length; ++i)
+        window.console[names[i]] = function() {}
+}
\ No newline at end of file

Added: sandbox/tschaub/geojson/lib/Firebug/infoIcon.png
===================================================================
(Binary files differ)


Property changes on: sandbox/tschaub/geojson/lib/Firebug/infoIcon.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: sandbox/tschaub/geojson/lib/Firebug/warningIcon.png
===================================================================
(Binary files differ)


Property changes on: sandbox/tschaub/geojson/lib/Firebug/warningIcon.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Modified: sandbox/tschaub/geojson/lib/OpenLayers/BaseTypes.js
===================================================================
--- sandbox/tschaub/geojson/lib/OpenLayers/BaseTypes.js	2007-05-23 20:18:45 UTC (rev 3163)
+++ sandbox/tschaub/geojson/lib/OpenLayers/BaseTypes.js	2007-05-23 22:54:22 UTC (rev 3164)
@@ -936,3 +936,25 @@
     return __method.call(object, event || window.event);
   }
 };
+
+/*********************
+ *                   *
+ *      CONSOLE      * 
+ *                   * 
+ *********************/
+
+/**
+ * Create empty functions for all console methods.  The real value of these
+ * properties will be set if the Firebug/DebugOpenLayers.js script is included
+ * after OpenLayers.js.
+ */
+
+OpenLayers.console = {};
+(function() {
+    var methods = ['log', 'debug', 'info', 'warn', 'error', 'assert',
+                   'dir', 'dirxml', 'trace', 'group', 'groupEnd', 'time',
+                   'timeEnd', 'profile', 'profileEnd', 'count'];
+    for(var i=0; i<methods.length; ++i) {
+        OpenLayers.console[methods[i]] = function() {};
+    }
+})();
\ No newline at end of file

Modified: sandbox/tschaub/geojson/lib/OpenLayers/Format/GeoJSON.js
===================================================================
--- sandbox/tschaub/geojson/lib/OpenLayers/Format/GeoJSON.js	2007-05-23 20:18:45 UTC (rev 3163)
+++ sandbox/tschaub/geojson/lib/OpenLayers/Format/GeoJSON.js	2007-05-23 22:54:22 UTC (rev 3164)
@@ -13,38 +13,146 @@
     /**
      * Deserialize a GeoJSON string.
      * @param {String} json A GeoJSON string
+     * @param {String} type Optional string that determines the structure of
+     *                      the output.  Supported values are "Geometry",
+     *                      "Feature", "GeometryCollection", and
+     *                      "FeatureCollection".  If absent or null, a
+     *                      default of "FeatureCollection" is assumed.
      * @param {Function} filter A function which will be called for every key
      *                          and value at every level of the final result.
      *                          Each value will be replaced by the result of
      *                          the filter function. This can be used to reform
      *                          generic objects into instances of classes, or to
      *                          transform date strings into Date objects.
-     * @returns {Array(OpenLayers.Feature.Vector)} An array of features
+     * @returns {Object} The return depends on the value of the type argument.
+     *                   If type is "FeatureCollection" (the default), the
+     *                   return will be an array of OpenLayers.Feature.Vector.
+     *                   If type is "Geometry", the input json must represent a
+     *                   single geometry, and the return will be an
+     *                   OpenLayers.Geometry.  If type is "Feature", the input
+     *                   json must represent a single feature, and the return
+     *                   will be an OpenLayers.Feature.Vector.  If type is
+     *                   "GeometryCollection", the input json must represent
+     *                   a geometry collection, and the return will be an array
+     *                   of OpenLayers.Geometry.
      */
-    read: function(json, filter) {
+    read: function(json, type, filter) {
+        type = (!!type) ? type : "FeatureCollection";
+        var results = null;
         var obj = OpenLayers.Format.JSON.prototype.read.apply(this, [json, filter]);
-        var features = [];
-        var f = null;
-        if(!(obj.features instanceof Array)) {
-            // deal with bad GeoJSON
-            //OpenLayers.console.error("Bad GeoJSON: " + obj);
-        } else {
-            for(var i=0; i<obj.features.length; ++i) {
-                try {
-                    f = this.parseFeature(obj.features[i]);
-                    features.push(f);
-                } catch(err) {
-                    // deal with bad features
-                    //OpenLayers.console.error('Bad Features:' + err);
-                }
+        if(!obj) {
+            OpenLayers.console.error("Bad JSON: " + json);
+        } else if(typeof(obj.type) != "string") {
+            OpenLayers.console.error("Bad GeoJSON - no type: " + json);
+        } else if(this.isValidType(obj, type)) {
+            switch(type) {
+                case "Geometry":
+                    try {
+                        results = this.parseGeometry(obj);
+                    } catch(err) {
+                        OpenLayers.console.error(err);
+                    }
+                    break;
+                case "Feature":
+                    try {
+                        results = this.parseFeature(obj);
+                        resutls.type = "Feature";
+                    } catch(err) {
+                        OpenLayers.console.error(err);
+                    }
+                    break;
+                case "GeometryCollection":
+                    results = [];
+                    for(var i=0; i<obj.geometries.length; ++i) {
+                        try {
+                            results.push(this.parseGeometry(obj.geometries[i]));
+                        } catch(err) {
+                            results = null;
+                            OpenLayers.console.error(err);
+                        }
+                    }
+                    break;
+                case "FeatureCollection":
+                    // for type FeatureCollection, we allow input to be any type
+                    results = [];
+                    switch(obj.type) {
+                        case "Feature":
+                            try {
+                                results.push(this.parseFeature(obj));
+                            } catch(err) {
+                                results = null;
+                                OpenLayers.console.error(err);
+                            }
+                            break;
+                        case "FeatureCollection":
+                            for(var i=0; i<obj.members.length; ++i) {
+                                try {
+                                    results.push(this.parseFeature(obj.members[i]));
+                                } catch(err) {
+                                    results = null;
+                                    OpenLayers.console.error(err);
+                                }
+                            }
+                            break;
+                        case "GeometryCollection":
+                            for(var i=0; i<obj.members.length; ++i) {
+                                try {
+                                    var geom = this.parseGeometry(obj.members[i]);
+                                    results.push(new OpenLayers.Feature.Vector(geom));
+                                } catch(err) {
+                                    results = null;
+                                    OpenLayers.console.error(err);
+                                }
+                            }
+                            break;
+                        default:
+                            try {
+                                var geom = this.parseGeometry(obj);
+                                results.push(new OpenLayers.Feature.Vector(geom));
+                            } catch(err) {
+                                results = null;
+                                OpenLayers.console.error(err);
+                            }
+                    }
+                break;
             }
         }
-        return features;
+        return results;
     },
     
+    isValidType: function(obj, type) {
+        var valid = false;
+        switch(type) {
+            case "Geometry":
+                if(OpenLayers.Util.indexOf(["Point", "MultiPoint", "LineString",
+                                            "MultiLineString", "Polygon",
+                                            "MutiPolygon", "Box"], obj.type) == -1) {
+                    // unsupported geometry type
+                    OpenLayers.console.error("Unsupported geometry type: " +
+                                              obj.type);
+                } else {
+                    valid = true;
+                }
+                break;
+            case "FeatureCollection":
+                // allow for any type to be converted to a feature collection
+                valid = true;
+                break
+            default:
+                // for GeometryCollection and Feature, types must match
+                if(obj.type == type) {
+                    valid = true;
+                } else {
+                    OpenLayers.console.error("Cannot convert types from " +
+                                              obj.type + " to " + type);
+                }
+        }
+        return valid;
+    },
+    
     /**
      * Convert a feature object from GeoJSON into an OpenLayers.Feature.Vector.
-     * @param {Object} obj An object created from a GeoJSON fragment
+     * @param {Object} obj An object created from a GeoJSON object
      * @returns {OpenLayers.Feature.Vector} A feature
      * @private
      */
@@ -63,7 +171,7 @@
     
     /**
      * Convert a geometry object from GeoJSON into an OpenLayers.Geometry.
-     * @param {Object} obj An object created from a GeoJSON fragment
+     * @param {Object} obj An object created from a GeoJSON object
      * @returns {OpenLayers.Geometry} A geometry
      * @private
      */
@@ -97,14 +205,10 @@
          * @private
          */
         "point": function(array) {
-            if(array.length != 1) {
-                throw "Bad point coordinates: " + array;
+            if(array.length != 2) {
+                throw "Only 2D points are supported: " + array;
             }
-            if(array[0].length != 2) {
-                throw "Only 2D points are supported: " + array[0];
-            }
-            // let this [[x, y]] be gone please
-            return new OpenLayers.Geometry.Point(array[0][0], array[0][1]);
+            return new OpenLayers.Geometry.Point(array[0], array[1]);
         },
         
         /**
@@ -117,7 +221,11 @@
             var points = [];
             var p = null;
             for(var i=0; i<array.length; ++i) {
-                p = this.parseCoords["point"].apply(this, [[array[i]]]);
+                try {
+                    p = this.parseCoords["point"].apply(this, [array[i]]);
+                } catch(err) {
+                    throw err;
+                }
                 points.push(p);
             }
             return new OpenLayers.Geometry.MultiPoint(points);
@@ -133,7 +241,11 @@
             var points = [];
             var p = null;
             for(var i=0; i<array.length; ++i) {
-                p = this.parseCoords["point"].apply(this, [[array[i]]]);
+                try {
+                    p = this.parseCoords["point"].apply(this, [array[i]]);
+                } catch(err) {
+                    throw err;
+                }
                 points.push(p);
             }
             return new OpenLayers.Geometry.LineString(points);
@@ -149,7 +261,11 @@
             var lines = [];
             var l = null;
             for(var i=0; i<array.length; ++i) {
-                l = this.parseCoords["linestring"].apply(this, [array[i]]);
+                try {
+                    l = this.parseCoords["linestring"].apply(this, [array[i]]);
+                } catch(err) {
+                    throw err;
+                }
                 lines.push(l);
             }
             return new OpenLayers.Geometry.MultiLineString(lines);
@@ -165,13 +281,17 @@
             var rings = [];
             var r, l;
             for(var i=0; i<array.length; ++i) {
-                l = this.parseCoords["linestring"].apply(this, [array[i]]);
+                try {
+                    l = this.parseCoords["linestring"].apply(this, [array[i]]);
+                } catch(err) {
+                    throw err;
+                }
                 r = new OpenLayers.Geometry.LinearRing(l.components);
                 rings.push(r);
             }
             return new OpenLayers.Geometry.Polygon(rings);
         },
-        
+
         /**
          * Convert a coordinate array from GeoJSON into an OpenLayers.Geometry.
          * @param {Object} array The coordinates array from the GeoJSON fragment
@@ -182,60 +302,122 @@
             var polys = [];
             var p = null;
             for(var i=0; i<array.length; ++i) {
-                p = this.parseCoords["polygon"].apply(this, [array[i]]);
+                try {
+                    p = this.parseCoords["polygon"].apply(this, [array[i]]);
+                } catch(err) {
+                    throw err;
+                }
                 polys.push(p);
             }
             return new OpenLayers.Geometry.MultiPolygon(polys);
+        },
+
+        /**
+         * Convert a coordinate array from GeoJSON into an OpenLayers.Geometry.
+         * @param {Object} array The coordinates array from the GeoJSON fragment
+         * @returns {OpenLayers.Geometry} A geometry
+         * @private
+         */
+        "box": function(array) {
+            if(array.length != 4) {
+                throw "GeoJSON box coordinates must have 4 elements";
+            }
+            return new OpenLayers.Geometry.Polygon([
+                new OpenLayers.Geometry.LinearRing([
+                    new OpenLayers.Geometry.Point(array[0], array[1]),
+                    new OpenLayers.Geometry.Point(array[2], array[1]),
+                    new OpenLayers.Geometry.Point(array[2], array[3]),
+                    new OpenLayers.Geometry.Point(array[0], array[3]),
+                    new OpenLayers.Geometry.Point(array[0], array[1])
+                ])
+            ]);
         }
 
     },
 
     /**
-     * Serialize an array of features into a GeoJSON string.
-     * @param {Array} features An array of OpenLayers.Feature.Vector
-     * @returns {String} The GeoJSON string representation of the input features
+     * Serialize a feature, geometry, array of features, or array of geometries
+     * into a GeoJSON string.
+     * @param {Object} obj An OpenLayers.Feature.Vector, OpenLayers.Geometry,
+     *                    or an array of either features or geometries.
+     * @returns {String} The GeoJSON string representation of the input geometry,
+     *                   features, array of geometries, or array of features.
      */
-    write: function(features) {
-        var feature, geometry, type, data, crs;
-        var array = [];
-        try {
-            crs = features[0].layer.projection;
-        } catch(e) {
-            crs = null;
-        }
-        for(var i=0; i<features.length; ++i) {
-            feature = features[i];
-            geometry = feature.geometry;
-            type = geometry.CLASS_NAME.split('.')[2];
-            data = this.extract[type.toLowerCase()].apply(this, [geometry]);
-            // please let this go away
-            if(type == "Point") {
-                data = [data];
-            }    
-            array.push({
-                'id': feature.id,
-                'properties': feature.attributes,
-                'geometry': {
-                    'type': type,
-                    'coordinates': data
+    write: function(obj) {
+        var geojson = {
+            "type": null
+        };
+        if(obj instanceof Array) {
+            geojson.members = [];
+            for(var i=0; i<obj.length; ++i) {
+                var element = obj[i];
+                if(element instanceof OpenLayers.Feature.Vector) {
+                    if(geojson.type == null) {
+                        geojson.type = "FeatureCollection";
+                    } else if(geojson.type != "FeatureCollection") {
+                        OpenLayers.console.error("FeatureCollection only supports collections of features: " + element);
+                        break;
+                    }
+                    geojson.members.push(this.extract.feature.apply(this, [element]));
+                } else if (element instanceof OpenLayers.Geometry) {
+                    if(geojson.type == null) {
+                        geojson.type = "GeometryCollection";
+                    } else if(geojson.type != "GeometryCollection") {
+                        OpenLayers.console.error("GeometryCollection only supports collections of geometries: " + element);
+                        break;
+                    }
+                    geojson.members.push(this.extract.geometry.apply(this, [element]));
                 }
-            });
+            }
+        } else if (obj instanceof OpenLayers.Geometry) {
+            geojson = this.extract.geometry.apply(this, [obj]);
+        } else if (obj instanceof OpenLayers.Feature.Vector) {
+            geojson = this.extract.feature.apply(this, [obj]);
         }
-        return OpenLayers.Format.JSON.prototype.write.apply(this, [{
-            'features': array,
-            'crs': crs
-        }]);
+        return OpenLayers.Format.JSON.prototype.write.apply(this, [geojson]);
     },
     
     /**
-     * Object with properties corresponding to the geometry types.
+     * Object with properties corresponding to the GeoJSON types.
      * Property values are functions that do the actual value extraction.
      */
     extract: {
         /**
+         * Return a partial GeoJSON object representing a single feature.
+         * @param {OpenLayers.Feature.Vector} feature
+         * @returns {Object} An object representing the point
+         * @private
+         */
+        'feature': function(feature) {
+            var geom = this.extract.geometry.apply(this, [feature.geometry]);
+            return {
+                "type": "Feature",
+                "id": feature.id,
+                "properties": feature.attributes,
+                "geometry": geom
+            }
+        },
+        
+        /**
+         * Return a GeoJSON object representing a single geometry.
+         * @param {OpenLayers.Geometry} point
+         * @returns {Object} An object representing the geometry
+         * @private
+         */
+        'geometry': function(geometry) {
+            var geometryType = geometry.CLASS_NAME.split('.')[2];
+            var data = this.extract[geometryType.toLowerCase()].apply(this, [geometry]);
+            return {
+                "type": geometryType,
+                "coordinates": data
+            }
+        },
+
+        /**
          * Return an array of coordinates from a point.
          * @param {OpenLayers.Geometry.Point} point
          * @returns {Array} An array of coordinates representing the point
+         * @private
          */
         'point': function(point) {
             return [point.x, point.y];
@@ -246,6 +428,7 @@
          * @param {OpenLayers.Geometry.MultiPoint} multipoint
          * @returns {Array} An array of point coordinate arrays representing
          *                  the multipoint
+         * @private
          */
         'multipoint': function(multipoint) {
             var array = [];
@@ -260,6 +443,7 @@
          * @param {OpenLayers.Geometry.LineString} linestring
          * @returns {Array} An array of coordinate arrays representing
          *                  the linestring
+         * @private
          */
         'linestring': function(linestring) {
             var array = [];
@@ -274,6 +458,7 @@
          * @param {OpenLayers.Geometry.MultiLineString} linestring
          * @returns {Array} An array of linestring arrays representing
          *                  the multilinestring
+         * @private
          */
         'multilinestring': function(multilinestring) {
             var array = [];
@@ -287,6 +472,7 @@
          * Return an array of linear ring arrays from a polygon.
          * @param {OpenLayers.Geometry.Polygon} polygon
          * @returns {Array} An array of linear ring arrays representing the polygon
+         * @private
          */
         'polygon': function(polygon) {
             var array = [];
@@ -301,6 +487,7 @@
          * @param {OpenLayers.Geometry.MultiPolygon} multipolygon
          * @returns {Array} An array of polygon arrays representing
          *                  the multipolygon
+         * @private
          */
         'multipolygon': function(multipolygon) {
             var array = [];



More information about the Commits mailing list