prevent errors when closing sidebar
[rails.git] / app / views / browse / start.rjs
1 page.replace_html :sidebar_title, 'Data'
2 page.replace_html :sidebar_content, :partial => 'start'
3 page << <<EOJ
4     
5     var gml, sf, objList, currentFeature, featureList, mode = "auto", currentBounds, browsing;
6     OpenLayers.Feature.Vector.style['default'].strokeWidth = 3;
7     OpenLayers.Feature.Vector.style['default'].cursor = "pointer";
8     
9     function start() {
10         openSidebar({ onclose: stopBrowse });
11         var vectors = new OpenLayers.Layer.Vector();
12     
13         box = new OpenLayers.Control.DrawFeature(vectors, OpenLayers.Handler.RegularPolygon, { 
14           handlerOptions: {
15             sides: 4,
16             snapAngle: 90,
17             irregular: true,
18             persist: true,
19             callbacks: { done: endDrag }
20           }
21         });
22         map.addControl(box);
23         map.events.register("moveend", map, showData);
24         map.events.triggerEvent("moveend");
25         browsing = true;
26     }
27
28     function showData() {
29         if (mode == "manual") { return; }
30         if (map.getZoom() >= 15) {
31             useMap();
32         } else {
33             $("status").innerHTML = "Zoom in or Select an area of the map to view.";
34         }    
35     }
36     
37     function stopBrowse() {
38         if (gml) {
39             gml.destroy();
40             gml = null; 
41         } 
42         if (sf) {   
43             sf.destroy();  
44             sf = null;
45         } 
46         if (currentFeature) {
47             currentFeature.destroy(); 
48             currentFeature = null; 
49         } 
50         map.events.unregister("moveend", map, showData);
51         browsing = false; 
52     }
53     
54     function startDrag() {
55       $("drag_box").innerHTML='Drag a box on the map to select an area';
56        box.activate(); 
57        return false;
58     };
59     $("drag_box").onclick = startDrag;
60     
61     function useMap() {
62         var bounds = map.getExtent();
63         var projected = bounds.clone().transform(map.getProjectionObject(), epsg4326);
64         if (!currentBounds || !currentBounds.containsBounds(projected)) {
65             var center = bounds.getCenterLonLat();
66             var tileWidth = bounds.getWidth() * 1.2;
67             var tileHeight = bounds.getHeight() * 1.2;
68             var tileBounds =
69                 new OpenLayers.Bounds(center.lon - (tileWidth / 2),
70                                       center.lat - (tileHeight / 2),
71                                       center.lon + (tileWidth / 2),
72                                       center.lat + (tileHeight / 2));
73
74             currentBounds = tileBounds;
75             getData(tileBounds);
76             mode = "auto";
77             $("drag_box").style.display="inline";
78             $("use_map").style.display="none";
79         }
80         return false;
81     }
82     $("use_map").onclick = useMap;
83     
84     function endDrag(bbox) {
85         var bounds = bbox.getBounds();
86         box.deactivate();
87         getData(bounds);
88         $("drag_box").innerHTML = "Manually select a different area";
89         mode = "manual";  
90         $("use_map").style.display="inline";
91         $("drag_box").style.display="none";
92     }
93     
94     function displayFeatureWarning() {
95         $("status").innerHTML = "";
96         var div = document.createElement("div");
97         var p = document.createElement("p");
98         p.appendChild(document.createTextNode("You have loaded an area which contains " + featureList.length + " features. In general, some browsers may not cope well with displaying this quantity of data. Generally, browsers work best at displaying less than 100 features at a time: doing anything else may make your browser slow/unresponsive. If you are sure you want to display this data, you may do so by clicking the button below.")); 
99         div.appendChild(p);
100         var input = document.createElement("input");
101         input.type = "submit";
102         input.value = "Load Data";
103         input.onclick = loadFeatureList;
104         div.appendChild(input); 
105         $("object").innerHTML="";
106         $("object").appendChild(div);
107     }
108     
109     function loadFeatureList() {
110         gml.addFeatures(featureList);
111         gml.events.triggerEvent("loadend");
112         return false;
113     }    
114
115     function customDataLoader(request) { 
116         if (!browsing) { return; } 
117         var doc = request.responseXML;
118         
119         if (!doc || !doc.documentElement) {
120             doc = request.responseText;
121         }
122         
123         var options = {};
124         
125         OpenLayers.Util.extend(options, this.formatOptions);
126         if (this.map && !this.projection.equals(this.map.getProjectionObject())) {
127             options.externalProjection = this.projection;
128             options.internalProjection = this.map.getProjectionObject();
129         }    
130         
131         var gml = this.format ? new this.format(options) : new OpenLayers.Format.GML(options);
132         var features = gml.read(doc);
133         if (!this.maxFeatures || features.length <= this.maxFeatures) {
134             this.addFeatures(features);
135             this.events.triggerEvent("loadend");
136             featureList = []; 
137         } else {
138             featureList = features;
139             displayFeatureWarning();
140         }
141     }
142
143     function getData(bounds) {
144         
145         bounds.transform(new OpenLayers.Projection("EPSG:900913"), new OpenLayers.Projection("EPSG:4326"));
146         var size = bounds.getWidth() * bounds.getHeight(); 
147         if (size > 0.25) {
148             $("status").innerHTML = "Unable to load: Bounding box size of " + size + " is too large. (Must be smaller than 0.25)<br />"; 
149             return;
150         }
151
152         var url = "/api/0.5/map?bbox="+bounds.toBBOX();
153         
154         loadGML(url);
155     }
156     function loadGML(url) {
157         $("status").innerHTML = "Loading...";
158         $("object").innerHTML = "";
159         if (!gml) {
160             var style = new OpenLayers.Style();
161             style.addRules([new OpenLayers.Rule( 
162               {'symbolizer': 
163                 {"Polygon": {'fillColor': '#ff0000', 'strokeColor': '#ff0000'},
164                  "Line": {'fillColor': '#ffff00', 'strokeColor': '#000000', strokeOpacity: '0.4'},
165                  "Point": {'fillColor': '#00ff00', 'strokeColor': '#00ff00'}}
166               }
167             )]);
168             gml = new OpenLayers.Layer.GML("Data",url, 
169                     {format: OpenLayers.Format.OSM, formatOptions: {checkTags: true},
170                      maxFeatures: 100, requestSuccess: customDataLoader,
171                      styleMap: new OpenLayers.StyleMap({'default': style, 'select': {'strokeColor': '#0000ff', strokeWidth: 8}})
172                     }
173             );
174             gml.events.register("loadend", gml, dataLoaded );
175             map.addLayer(gml);
176             
177             sf = new OpenLayers.Control.SelectFeature(gml, {'onSelect': onFeatureSelect});
178             sf.handler.stopDown = false;
179             sf.handler.stopUp = false;
180             map.addControl(sf);
181             sf.activate();
182              
183         } else {
184             gml.setUrl(url);
185         }
186
187         currentFeature = null;
188     }
189     function dataLoaded() {
190         if (!browsing) { return; } 
191         $("status").innerHTML = "Loaded " + this.features.length + " features. (<a href='"+ this.url+"'>API</a>)";
192         
193         objList = document.createElement("ul");
194         for (var i = 0; i < this.features.length; i++) {
195             var feature = this.features[i]; 
196             
197             // Type, for linking
198             var type ="way";
199             if (feature.geometry.CLASS_NAME == "OpenLayers.Geometry.Point") {
200                 type = "node";
201             }   
202             var nice_name = type.substr(0,1).toUpperCase() + type.substr(1,type.length); 
203             var li = document.createElement("li");
204             li.appendChild(document.createTextNode(nice_name + " "));
205             
206             // Link, for viewing in the tab
207             var link = document.createElement("a");
208             link.href =  "/browse/" + type + "/" + feature.osm_id; 
209             var name = feature.attributes.name || feature.osm_id;
210             link.appendChild(document.createTextNode(name));
211             link.feature = feature;
212             link.onclick = OpenLayers.Function.bind(viewFeatureLink, link);   
213             li.appendChild(link);
214
215             objList.appendChild(li);
216         }
217         $("object").innerHTML = "";
218         $("object").appendChild(objList); 
219     }
220     
221     function viewFeatureLink() {
222         var layer = this.feature.layer;
223         for (var i = 0; i < layer.selectedFeatures.length; i++) {
224             var f = layer.selectedFeatures[i]; 
225             layer.drawFeature(f, layer.styleMap.createSymbolizer(f, "default"));
226         }
227         onFeatureSelect(this.feature);
228         if (mode != "auto") {
229             map.setCenter(this.feature.geometry.getBounds().getCenterLonLat()); 
230         }
231         return false;
232     }
233     
234     function loadObjList() {
235         $("object").innerHTML="";
236         $("object").appendChild(objList);
237         return false;
238     }
239       
240     function onFeatureSelect(feature) {
241         // Unselect previously selected feature
242         if (currentFeature) {
243           currentFeature.layer.drawFeature(
244             currentFeature, currentFeature.layer.styleMap.createSymbolizer(currentFeature, "default")
245           );
246         }
247
248         // Redraw in selected style
249         feature.layer.drawFeature(
250           feature, feature.layer.styleMap.createSymbolizer(feature, "select")
251         );
252
253         // If the current object is the list, don't innerHTML="", since that could clar it.   
254         if ($("object").firstChild == objList) { 
255             $("object").removeChild(objList);
256         } else { 
257             $("object").innerHTML = "";
258         }   
259         
260         // Create a link back to the object list
261         var div = document.createElement("div");
262         var link = document.createElement("a");
263         link.href="#";
264         link.onclick = loadObjList;
265         link.appendChild(document.createTextNode("Back to Object List"));
266         div.appendChild(link)
267         $("object").appendChild(div);    
268         
269         // Now the list of attributes
270         var ul = document.createElement("ul");
271         var type = "way";
272         if (feature.geometry.CLASS_NAME == "OpenLayers.Geometry.Point") {
273             type = "node";
274         }    
275         var li = document.createElement("li");
276         var link = document.createElement("a");   
277         link.href =  "/browse/"+type+"/"+feature.osm_id;
278         link.appendChild(document.createTextNode(feature.osm_id));
279         li.appendChild(link);
280         ul.appendChild(li);
281         for (var key in feature.attributes) {
282             var li = document.createElement("li");
283             var b = document.createElement("b");
284             b.appendChild(document.createTextNode(key));
285             li.appendChild(b);
286             li.appendChild(document.createTextNode(": " + feature.attributes[key]));
287             ul.appendChild(li);
288         }
289         
290         var li = document.createElement("li");
291         var link = document.createElement("a");   
292         link.href =  "/browse/"+type+"/"+feature.osm_id+"/history";
293         link.appendChild(document.createTextNode("History"));
294         li.appendChild(link);
295         ul.appendChild(li);
296         link.onclick = OpenLayers.Function.bind(loadHistory, {type: type, feature: feature, link: link});
297         $("object").appendChild(ul);
298         
299         
300         // Stash the currently drawn feature
301         currentFeature = feature; 
302     }   
303     function loadHistory() {
304         this.link.href = "";
305         this.link.innerHTML = "Wait...";
306         new Ajax.Request("/api/0.5/"+this.type+"/"+this.feature.osm_id+"/history", {onComplete: OpenLayers.Function.bind(displayHistory, this)});
307         return false;
308     }
309     function displayHistory(request) {
310         if (currentFeature.osm_id != this.feature.osm_id || $("object").firstChild == objList)  { 
311             return false;
312         } 
313         this.link.parentNode.parentNode.removeChild(this.link.parentNode);
314         var doc = request.responseXML;
315         var div = document.createElement("div");
316         var h3 = document.createElement("h3"); 
317         h3.appendChild(document.createTextNode("History"));
318         div.appendChild(h3);
319         var nodes = doc.getElementsByTagName(this.type);
320         var history = document.createElement("ul");  
321         for (var i = nodes.length - 1; i >= 0; i--) {
322             var user = nodes[i].getAttribute("user") || "private user";
323             var timestamp = nodes[i].getAttribute("timestamp");
324             var item = document.createElement("li");
325             item.appendChild(document.createTextNode("Edited by " + user + " at " + timestamp));
326             history.appendChild(item);
327         }
328         div.appendChild(history);
329         var link = document.createElement("a");
330         link.appendChild(document.createTextNode("History"));
331         link.href = "/browse/"+this.type+"/"+this.feature.osm_id+"/history";
332         div.appendChild(link);
333         $("object").appendChild(div); 
334     }
335     
336     start();
337 EOJ