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