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