1b57f48a07c4ba6d296746513689b1501b44205b
[rails.git] / app / views / browse / start.js.erb
1 var browseBoxControl;
2 var browseMode = "auto";
3 var browseBounds;
4 var browseFeatureList;
5 var browseActiveFeature;
6 var browseDataLayer;
7 var browseSelectControl;
8 var browseObjectList;
9 var areasHidden = false;
10
11 OpenLayers.Feature.Vector.style['default'].strokeWidth = 3;
12 OpenLayers.Feature.Vector.style['default'].cursor = "pointer";
13     
14 function startBrowse() {
15   map.dataLayer.active = true;
16
17   $("#sidebar_title").html("<%=j t 'browse.start_rjs.data_frame_title' %>");
18   $("#sidebar_content").html("<%=j render :partial => "sidebar" %>");
19
20   openSidebar({ onclose: stopBrowse });
21
22   var vectors = new OpenLayers.Layer.Vector();
23     
24   browseBoxControl = new OpenLayers.Control.DrawFeature(vectors, OpenLayers.Handler.RegularPolygon, { 
25     handlerOptions: {
26       sides: 4,
27       snapAngle: 90,
28       irregular: true,
29       persist: true
30     }
31   });
32   browseBoxControl.handler.callbacks.done = endDrag;
33   map.addControl(browseBoxControl);
34
35   map.events.register("moveend", map, updateData);
36   map.events.triggerEvent("moveend");
37
38   $("#browse_select_view").click(useMap);
39
40   $("#browse_select_box").click(startDrag);
41
42   $("#browse_hide_areas_box").html("<%=j t 'browse.start_rjs.hide_areas' %>");
43   $("#browse_hide_areas_box").show();
44   $("#browse_hide_areas_box").click(hideAreas);
45 }
46
47 function updateData() {
48   if (browseMode == "auto") {
49     if (map.getZoom() >= 15) {
50         useMap(false);
51     } else {
52         setStatus("<%=j t 'browse.start_rjs.zoom_or_select' %>");
53     }    
54   }
55 }
56
57 function stopBrowse() {
58   if (map.dataLayer.active) {
59     map.dataLayer.active = false;
60
61     if (browseSelectControl) {   
62       browseSelectControl.destroy();  
63       browseSelectControl = null;
64     } 
65
66     if (browseBoxControl) {
67       browseBoxControl.destroy();
68       browseBoxControl = null;
69     }           
70
71     if (browseActiveFeature) {
72       browseActiveFeature.destroy(); 
73       browseActiveFeature = null; 
74     }
75
76     if (browseDataLayer) {
77       browseDataLayer.destroy();
78       browseDataLayer = null; 
79     } 
80
81     map.dataLayer.setVisibility(false);
82     map.events.unregister("moveend", map, updateData);
83   }    
84 }
85
86 function startDrag() {
87   $("#browse_select_box").html("<%=j t 'browse.start_rjs.drag_a_box' %>");
88
89   browseBoxControl.activate();
90
91   return false;
92 }
93
94 function useMap(reload) {
95   var bounds = map.getExtent();
96   var projected = bounds.clone().transform(map.getProjectionObject(), epsg4326);
97
98   if (!browseBounds || !browseBounds.containsBounds(projected)) {
99     var center = bounds.getCenterLonLat();
100     var tileWidth = bounds.getWidth() * 1.2;
101     var tileHeight = bounds.getHeight() * 1.2;
102     var tileBounds = new OpenLayers.Bounds(center.lon - (tileWidth / 2),
103                                            center.lat - (tileHeight / 2),
104                                            center.lon + (tileWidth / 2),
105                                            center.lat + (tileHeight / 2));
106
107     browseBounds = tileBounds;
108     getData(tileBounds, reload);
109
110     browseMode = "auto";
111
112     $("#browse_select_view").hide();
113   }
114
115   return false;
116 }
117
118 function hideAreas() {
119   $("#browse_hide_areas_box").html("<%=j t 'browse.start_rjs.show_areas' %>");
120   $("#browse_hide_areas_box").show();
121   $("#browse_hide_areas_box").click(showAreas);
122
123   areasHidden = true;
124
125   useMap(true);
126 }
127
128 function showAreas() {
129   $("#browse_hide_areas_box").html("<%=j t 'browse.start_rjs.hide_areas' %>");
130   $("#browse_hide_areas_box").show();
131   $("#browse_hide_areas_box").click(hideAreas);
132
133   areasHidden = false;
134
135   useMap(true);
136 }
137
138 function endDrag(bbox) {
139   var bounds = bbox.getBounds();
140   var projected = bounds.clone().transform(map.getProjectionObject(), epsg4326);
141
142   browseBoxControl.deactivate();
143   browseBounds = projected;
144   getData(bounds);
145
146   browseMode = "manual";  
147
148   $("#browse_select_box").html("<%=j t 'browse.start_rjs.manually_select' %>");
149   $("#browse_select_view").show();
150 }
151
152 function displayFeatureWarning(count, limit, callback) {
153   clearStatus();
154
155   var div = document.createElement("div");
156
157   var p = document.createElement("p");
158   p.appendChild(document.createTextNode(I18n.t("browse.start_rjs.loaded_an_area_with_num_features", { num_features: count, max_features: limit })));
159   div.appendChild(p);
160
161   var input = document.createElement("input");
162   input.type = "submit";
163   input.value = "<%=j t 'browse.start_rjs.load_data' %>";
164   input.onclick = callback;
165   div.appendChild(input); 
166
167   $("#browse_content").html("");
168   $("#browse_content").append(div);
169 }
170
171 function customDataLoader(resp, options) {
172   if (map.dataLayer.active) {
173     var request = resp.priv;
174     var doc = request.responseXML;
175
176     if (!doc || !doc.documentElement) {
177       doc = request.responseText;
178     }
179
180     resp.features = this.format.read(doc);
181
182     if (!this.maxFeatures || resp.features.length <= this.maxFeatures) {
183       options.callback.call(options.scope, resp);
184     } else {
185       displayFeatureWarning(resp.features.length, this.maxFeatures, function () {
186         options.callback.call(options.scope, resp);
187       });
188     }
189   }
190 }
191
192 function getData(bounds, reload) {
193   var projected = bounds.clone().transform(new OpenLayers.Projection("EPSG:900913"), new OpenLayers.Projection("EPSG:4326"));
194   var size = projected.getWidth() * projected.getHeight();
195
196   if (size > <%= MAX_REQUEST_AREA %>) {
197     setStatus(I18n.t("browse.start_rjs.unable_to_load_size", { max_bbox_size: <%= MAX_REQUEST_AREA %>, bbox_size: size }));
198   } else {
199     loadData("/api/<%= API_VERSION %>/map?bbox=" + projected.toBBOX(), reload);
200   }
201 }
202
203 function loadData(url, reload) {
204   setStatus("<%=j t 'browse.start_rjs.loading' %>");
205
206   $("#browse_content").empty();
207
208   var formatOptions = {
209     checkTags: true,
210     interestingTagsExclude: ['source','source_ref','source:ref','history','attribution','created_by','tiger:county','tiger:tlid','tiger:upload_uuid']
211   };
212
213   if (areasHidden) formatOptions.areaTags = [];
214
215   if (!browseDataLayer || reload) {
216     var style = new OpenLayers.Style();
217
218     style.addRules([new OpenLayers.Rule({
219       symbolizer: {
220         Polygon: { fillColor: '#ff0000', strokeColor: '#ff0000' },
221         Line: { fillColor: '#ffff00', strokeColor: '#000000', strokeOpacity: '0.4' },
222         Point: { fillColor: '#00ff00', strokeColor: '#00ff00' }
223       }
224     })]);
225
226     if (browseDataLayer) browseDataLayer.destroyFeatures();
227
228     browseDataLayer = new OpenLayers.Layer.Vector("Data", {
229       strategies: [ 
230         new OpenLayers.Strategy.Fixed()
231       ],
232       protocol: new OpenLayers.Protocol.HTTP({
233         url: url,
234         format: new OpenLayers.Format.OSM(formatOptions),
235         maxFeatures: <%= @max_features %>,
236         handleRead: customDataLoader
237       }),
238       projection: new OpenLayers.Projection("EPSG:4326"),
239       displayInLayerSwitcher: false,
240       styleMap: new OpenLayers.StyleMap({
241         'default': style,
242         'select': { strokeColor: '#0000ff', strokeWidth: 8 }
243       })
244     });
245     browseDataLayer.events.register("loadend", browseDataLayer, dataLoaded );
246     map.addLayer(browseDataLayer);
247             
248     browseSelectControl = new OpenLayers.Control.SelectFeature(browseDataLayer, { onSelect: onFeatureSelect });
249     browseSelectControl.handlers.feature.stopDown = false;
250     browseSelectControl.handlers.feature.stopUp = false;
251     map.addControl(browseSelectControl);
252     browseSelectControl.activate();
253   } else {
254     browseDataLayer.destroyFeatures();
255     browseDataLayer.refresh({ url: url });
256   }
257
258   browseActiveFeature = null;
259 }
260
261 function dataLoaded() {
262   if (this.map.dataLayer.active) {
263     clearStatus();
264
265     browseObjectList = document.createElement("div");
266
267     var heading = document.createElement("p");
268     heading.className = "browse_heading";
269     heading.appendChild(document.createTextNode("<%=j t 'browse.start_rjs.object_list.heading' %>"));
270     browseObjectList.appendChild(heading);
271
272     var list = document.createElement("ul");
273
274     for (var i = 0; i < this.features.length; i++) {
275       var feature = this.features[i]; 
276             
277       // Type, for linking
278       var type = featureType(feature);
279       var typeName = featureTypeName(feature);
280       var li = document.createElement("li");
281       li.appendChild(document.createTextNode(typeName + " "));
282             
283       // Link, for viewing in the tab
284       var link = document.createElement("a");
285       link.href =  "/browse/" + type + "/" + feature.osm_id; 
286       var name = featureName(feature);
287       link.appendChild(document.createTextNode(name));
288       link.feature = feature;
289       link.onclick = OpenLayers.Function.bind(viewFeatureLink, link);   
290       li.appendChild(link);
291
292       list.appendChild(li);
293     }
294
295     browseObjectList.appendChild(list);
296
297     var link = document.createElement("a");
298     link.href = this.protocol.url;
299     link.appendChild(document.createTextNode("<%=j t 'browse.start_rjs.object_list.api' %>"));
300     browseObjectList.appendChild(link);
301
302     $("#browse_content").html(browseObjectList); 
303   }
304 }
305     
306 function viewFeatureLink() {
307   var layer = this.feature.layer;
308
309   for (var i = 0; i < layer.selectedFeatures.length; i++) {
310     var f = layer.selectedFeatures[i]; 
311     layer.drawFeature(f, layer.styleMap.createSymbolizer(f, "default"));
312   }
313
314   onFeatureSelect(this.feature);
315
316   if (browseMode != "auto") {
317     map.setCenter(this.feature.geometry.getBounds().getCenterLonLat()); 
318   }
319
320   return false;
321 }
322     
323 function loadObjectList() {
324   $("#browse_content").empty();
325   $("#browse_content").append(browseObjectList);
326
327   return false;
328 }
329       
330 function onFeatureSelect(feature) {
331   // Unselect previously selected feature
332   if (browseActiveFeature) {
333     browseActiveFeature.layer.drawFeature(
334       browseActiveFeature, 
335       browseActiveFeature.layer.styleMap.createSymbolizer(browseActiveFeature, "default")
336     );
337   }
338
339   // Redraw in selected style
340   feature.layer.drawFeature(
341     feature, feature.layer.styleMap.createSymbolizer(feature, "select")
342   );
343
344   // If the current object is the list, don't innerHTML="", since that could clear it.
345   if ($("#browse_content").firstChild == browseObjectList) { 
346     $("#browse_content").removeChild(browseObjectList);
347   } else { 
348     $("#browse_content").empty();
349   }   
350         
351   // Create a link back to the object list
352   var div = document.createElement("div");
353   div.style.textAlign = "center";
354   div.style.marginBottom = "20px";
355   $("#browse_content").append(div);
356   var link = document.createElement("a");
357   link.href = "#";
358   link.onclick = loadObjectList;
359   link.appendChild(document.createTextNode("<%=j t 'browse.start_rjs.object_list.back' %>"));
360   div.appendChild(link);
361
362   var table = document.createElement("table");
363   table.width = "100%";
364   table.className = "browse_heading";
365   $("#browse_content").append(table);
366
367   var tr = document.createElement("tr");
368   table.appendChild(tr);
369
370   var heading = document.createElement("td");
371   heading.appendChild(document.createTextNode(featureNameSelect(feature)));
372   tr.appendChild(heading);
373
374   var td = document.createElement("td");
375   td.align = "right";
376   tr.appendChild(td);
377
378   var type = featureType(feature);
379   var link = document.createElement("a");   
380   link.href = "/browse/" + type + "/" + feature.osm_id;
381   link.appendChild(document.createTextNode("<%=j t 'browse.start_rjs.object_list.details' %>"));
382   td.appendChild(link);
383
384   var div = document.createElement("div");
385   div.className = "browse_details";
386
387   $("#browse_content").append(div);
388
389   // Now the list of attributes
390   var ul = document.createElement("ul");
391   for (var key in feature.attributes) {
392     var li = document.createElement("li");
393     var b = document.createElement("b");
394     b.appendChild(document.createTextNode(key));
395     li.appendChild(b);
396     li.appendChild(document.createTextNode(": " + feature.attributes[key]));
397     ul.appendChild(li);
398   }
399         
400   div.appendChild(ul);
401         
402   var link = document.createElement("a");   
403   link.href =  "/browse/" + type + "/" + feature.osm_id + "/history";
404   link.appendChild(document.createTextNode("<%=j t 'browse.start_rjs.show_history' %>"));
405   link.onclick = OpenLayers.Function.bind(loadHistory, {
406     type: type, feature: feature, link: link
407   });
408         
409   div.appendChild(link);
410
411   // Stash the currently drawn feature
412   browseActiveFeature = feature; 
413 }   
414
415 function loadHistory() {
416   this.link.href = "";
417   this.link.innerHTML = "<%=j t 'browse.start_rjs.wait' %>";
418
419   $.ajax("/api/<%= API_VERSION %>/" + this.type + "/" + this.feature.osm_id + "/history", {
420     complete: OpenLayers.Function.bind(displayHistory, this)
421   });
422
423   return false;
424 }
425
426 function displayHistory(request) {
427   if (browseActiveFeature.osm_id != this.feature.osm_id || $("#browse_content").firstChild == browseObjectList)  { 
428       return false;
429   } 
430
431   this.link.parentNode.removeChild(this.link);
432
433   var doc = request.responseXML;
434
435   var table = document.createElement("table");
436   table.width = "100%";
437   table.className = "browse_heading";
438   $("#browse_content").append(table);
439
440   var tr = document.createElement("tr");
441   table.appendChild(tr);
442
443   var heading = document.createElement("td");
444   heading.appendChild(document.createTextNode(I18n.t("browse.start_rjs.history_for_feature", { feature: featureNameHistory(this.feature) })));
445   tr.appendChild(heading);
446
447   var td = document.createElement("td");
448   td.align = "right";
449   tr.appendChild(td);
450
451   var link = document.createElement("a");   
452   link.href = "/browse/" + this.type + "/" + this.feature.osm_id + "/history";
453   link.appendChild(document.createTextNode("<%=j t 'browse.start_rjs.details' %>"));
454   td.appendChild(link);
455
456   var div = document.createElement("div");
457   div.className = "browse_details";
458
459   var nodes = doc.getElementsByTagName(this.type);
460   var history = document.createElement("ul");  
461   for (var i = nodes.length - 1; i >= 0; i--) {
462     var user = nodes[i].getAttribute("user") || "<%=j t 'browse.start_rjs.private_user' %>";
463     var timestamp = nodes[i].getAttribute("timestamp");
464     var item = document.createElement("li");
465     item.appendChild(document.createTextNode(I18n.t("browse.start_rjs.edited_by_user_at_timestamp", { user: user, timestamp: timestamp })));
466     history.appendChild(item);
467   }
468   div.appendChild(history);
469
470   $("#browse_content").append(div); 
471 }
472
473 function featureType(feature) {
474   if (feature.geometry.CLASS_NAME == "OpenLayers.Geometry.Point") {
475     return "node";
476   } else {
477     return "way";
478   }
479 }
480
481 function featureTypeName(feature) {
482   if (featureType(feature) == "node") {
483     return "<%=j t 'browse.start_rjs.object_list.type.node' %>";
484   } else if (featureType(feature) == "way") {
485     return "<%=j t 'browse.start_rjs.object_list.type.way' %>";
486   }
487 }
488
489 function featureName(feature) {
490   if (feature.attributes['name:<%= I18n.locale %>']) {
491     return feature.attributes['name:<%= I18n.locale %>'];
492   } else if (feature.attributes.name) {
493     return feature.attributes.name;
494   } else {
495     return feature.osm_id;
496   }
497 }
498
499 function featureNameSelect(feature) {
500   if (feature.attributes['name:<%= I18n.locale %>']) {
501     return feature.attributes['name:<%= I18n.locale %>'];
502   } else if (feature.attributes.name) {
503     return feature.attributes.name;
504   } else if (featureType(feature) == "node") {
505     return I18n.t("browse.start_rjs.object_list.selected.type.node", { id: feature.osm_id });
506   } else if (featureType(feature) == "way") {
507     return I18n.t("browse.start_rjs.object_list.selected.type.way", { id: feature.osm_id });
508   }
509 }
510
511 function featureNameHistory(feature) {
512   if (feature.attributes['name:<%= I18n.locale %>']) {
513     return feature.attributes['name:<%= I18n.locale %>'];
514   } else if (feature.attributes.name) {
515     return feature.attributes.name;
516   } else if (featureType(feature) == "node") {
517     return I18n.t("browse.start_rjs.object_list.history.type.node", { id: feature.osm_id });
518   } else if (featureType(feature) == "way") {
519     return I18n.t("browse.start_rjs.object_list.history.type.way", { id: feature.osm_id });
520   }
521 }
522
523 function setStatus(status) {
524   $("#browse_status").html(status);
525   $("#browse_status").show();
526 }
527   
528 function clearStatus() {
529   $("#browse_status").html("");
530   $("#browse_status").hide();
531 }
532
533 startBrowse();