Reduce interpolation in browse/start.js.erb
[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(sidebarHtml) {
15   map.dataLayer.active = true;
16
17   $("#sidebar_title").html(I18n.t('browse.start_rjs.data_frame_title'));
18   $("#sidebar_content").html(sidebarHtml);
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(I18n.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(I18n.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(I18n.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(I18n.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(I18n.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(I18n.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 = I18n.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 > OSM.MAX_REQUEST_AREA) {
197     setStatus(I18n.t("browse.start_rjs.unable_to_load_size", { max_bbox_size: OSM.MAX_REQUEST_AREA, bbox_size: size }));
198   } else {
199     loadData("/api/" + OSM.API_VERSION + "/map?bbox=" + projected.toBBOX(), reload);
200   }
201 }
202
203 function loadData(url, reload) {
204   setStatus(I18n.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     var maxFeatures = 2000;
229
230     /*@cc_on
231       if (navigator.appVersion < 8) {
232         maxFeatures = 100;
233       } else if (navigator.appVersion < 9) {
234         maxFeatures = 500;
235       }
236     @*/
237
238     browseDataLayer = new OpenLayers.Layer.Vector("Data", {
239       strategies: [ 
240         new OpenLayers.Strategy.Fixed()
241       ],
242       protocol: new OpenLayers.Protocol.HTTP({
243         url: url,
244         format: new OpenLayers.Format.OSM(formatOptions),
245         maxFeatures: maxFeatures,
246         handleRead: customDataLoader
247       }),
248       projection: new OpenLayers.Projection("EPSG:4326"),
249       displayInLayerSwitcher: false,
250       styleMap: new OpenLayers.StyleMap({
251         'default': style,
252         'select': { strokeColor: '#0000ff', strokeWidth: 8 }
253       })
254     });
255     browseDataLayer.events.register("loadend", browseDataLayer, dataLoaded );
256     map.addLayer(browseDataLayer);
257             
258     browseSelectControl = new OpenLayers.Control.SelectFeature(browseDataLayer, { onSelect: onFeatureSelect });
259     browseSelectControl.handlers.feature.stopDown = false;
260     browseSelectControl.handlers.feature.stopUp = false;
261     map.addControl(browseSelectControl);
262     browseSelectControl.activate();
263   } else {
264     browseDataLayer.destroyFeatures();
265     browseDataLayer.refresh({ url: url });
266   }
267
268   browseActiveFeature = null;
269 }
270
271 function dataLoaded() {
272   if (this.map.dataLayer.active) {
273     clearStatus();
274
275     browseObjectList = document.createElement("div");
276
277     var heading = document.createElement("p");
278     heading.className = "browse_heading";
279     heading.appendChild(document.createTextNode(I18n.t('browse.start_rjs.object_list.heading')));
280     browseObjectList.appendChild(heading);
281
282     var list = document.createElement("ul");
283
284     for (var i = 0; i < this.features.length; i++) {
285       var feature = this.features[i]; 
286             
287       // Type, for linking
288       var type = featureType(feature);
289       var typeName = featureTypeName(feature);
290       var li = document.createElement("li");
291       li.appendChild(document.createTextNode(typeName + " "));
292             
293       // Link, for viewing in the tab
294       var link = document.createElement("a");
295       link.href =  "/browse/" + type + "/" + feature.osm_id; 
296       var name = featureName(feature);
297       link.appendChild(document.createTextNode(name));
298       link.feature = feature;
299       link.onclick = OpenLayers.Function.bind(viewFeatureLink, link);   
300       li.appendChild(link);
301
302       list.appendChild(li);
303     }
304
305     browseObjectList.appendChild(list);
306
307     var link = document.createElement("a");
308     link.href = this.protocol.url;
309     link.appendChild(document.createTextNode(I18n.t('browse.start_rjs.object_list.api')));
310     browseObjectList.appendChild(link);
311
312     $("#browse_content").html(browseObjectList); 
313   }
314 }
315     
316 function viewFeatureLink() {
317   var layer = this.feature.layer;
318
319   for (var i = 0; i < layer.selectedFeatures.length; i++) {
320     var f = layer.selectedFeatures[i]; 
321     layer.drawFeature(f, layer.styleMap.createSymbolizer(f, "default"));
322   }
323
324   onFeatureSelect(this.feature);
325
326   if (browseMode != "auto") {
327     map.setCenter(this.feature.geometry.getBounds().getCenterLonLat()); 
328   }
329
330   return false;
331 }
332     
333 function loadObjectList() {
334   $("#browse_content").empty();
335   $("#browse_content").append(browseObjectList);
336
337   return false;
338 }
339       
340 function onFeatureSelect(feature) {
341   // Unselect previously selected feature
342   if (browseActiveFeature) {
343     browseActiveFeature.layer.drawFeature(
344       browseActiveFeature, 
345       browseActiveFeature.layer.styleMap.createSymbolizer(browseActiveFeature, "default")
346     );
347   }
348
349   // Redraw in selected style
350   feature.layer.drawFeature(
351     feature, feature.layer.styleMap.createSymbolizer(feature, "select")
352   );
353
354   // If the current object is the list, don't innerHTML="", since that could clear it.
355   if ($("#browse_content").firstChild == browseObjectList) { 
356     $("#browse_content").removeChild(browseObjectList);
357   } else { 
358     $("#browse_content").empty();
359   }   
360         
361   // Create a link back to the object list
362   var div = document.createElement("div");
363   div.style.textAlign = "center";
364   div.style.marginBottom = "20px";
365   $("#browse_content").append(div);
366   var link = document.createElement("a");
367   link.href = "#";
368   link.onclick = loadObjectList;
369   link.appendChild(document.createTextNode(I18n.t('browse.start_rjs.object_list.back')));
370   div.appendChild(link);
371
372   var table = document.createElement("table");
373   table.width = "100%";
374   table.className = "browse_heading";
375   $("#browse_content").append(table);
376
377   var tr = document.createElement("tr");
378   table.appendChild(tr);
379
380   var heading = document.createElement("td");
381   heading.appendChild(document.createTextNode(featureNameSelect(feature)));
382   tr.appendChild(heading);
383
384   var td = document.createElement("td");
385   td.align = "right";
386   tr.appendChild(td);
387
388   var type = featureType(feature);
389   var link = document.createElement("a");   
390   link.href = "/browse/" + type + "/" + feature.osm_id;
391   link.appendChild(document.createTextNode(I18n.t('browse.start_rjs.object_list.details')));
392   td.appendChild(link);
393
394   var div = document.createElement("div");
395   div.className = "browse_details";
396
397   $("#browse_content").append(div);
398
399   // Now the list of attributes
400   var ul = document.createElement("ul");
401   for (var key in feature.attributes) {
402     var li = document.createElement("li");
403     var b = document.createElement("b");
404     b.appendChild(document.createTextNode(key));
405     li.appendChild(b);
406     li.appendChild(document.createTextNode(": " + feature.attributes[key]));
407     ul.appendChild(li);
408   }
409         
410   div.appendChild(ul);
411         
412   var link = document.createElement("a");   
413   link.href =  "/browse/" + type + "/" + feature.osm_id + "/history";
414   link.appendChild(document.createTextNode(I18n.t('browse.start_rjs.show_history')));
415   link.onclick = OpenLayers.Function.bind(loadHistory, {
416     type: type, feature: feature, link: link
417   });
418         
419   div.appendChild(link);
420
421   // Stash the currently drawn feature
422   browseActiveFeature = feature; 
423 }   
424
425 function loadHistory() {
426   this.link.href = "";
427   this.link.innerHTML = I18n.t('browse.start_rjs.wait');
428
429   $.ajax("/api/" + OSM.API_VERSION + "/" + this.type + "/" + this.feature.osm_id + "/history", {
430     complete: OpenLayers.Function.bind(displayHistory, this)
431   });
432
433   return false;
434 }
435
436 function displayHistory(request) {
437   if (browseActiveFeature.osm_id != this.feature.osm_id || $("#browse_content").firstChild == browseObjectList)  { 
438       return false;
439   } 
440
441   this.link.parentNode.removeChild(this.link);
442
443   var doc = request.responseXML;
444
445   var table = document.createElement("table");
446   table.width = "100%";
447   table.className = "browse_heading";
448   $("#browse_content").append(table);
449
450   var tr = document.createElement("tr");
451   table.appendChild(tr);
452
453   var heading = document.createElement("td");
454   heading.appendChild(document.createTextNode(I18n.t("browse.start_rjs.history_for_feature", { feature: featureNameHistory(this.feature) })));
455   tr.appendChild(heading);
456
457   var td = document.createElement("td");
458   td.align = "right";
459   tr.appendChild(td);
460
461   var link = document.createElement("a");   
462   link.href = "/browse/" + this.type + "/" + this.feature.osm_id + "/history";
463   link.appendChild(document.createTextNode(I18n.t('browse.start_rjs.details')));
464   td.appendChild(link);
465
466   var div = document.createElement("div");
467   div.className = "browse_details";
468
469   var nodes = doc.getElementsByTagName(this.type);
470   var history = document.createElement("ul");  
471   for (var i = nodes.length - 1; i >= 0; i--) {
472     var user = nodes[i].getAttribute("user") || I18n.t('browse.start_rjs.private_user');
473     var timestamp = nodes[i].getAttribute("timestamp");
474     var item = document.createElement("li");
475     item.appendChild(document.createTextNode(I18n.t("browse.start_rjs.edited_by_user_at_timestamp", { user: user, timestamp: timestamp })));
476     history.appendChild(item);
477   }
478   div.appendChild(history);
479
480   $("#browse_content").append(div); 
481 }
482
483 function featureType(feature) {
484   if (feature.geometry.CLASS_NAME == "OpenLayers.Geometry.Point") {
485     return "node";
486   } else {
487     return "way";
488   }
489 }
490
491 function featureTypeName(feature) {
492   if (featureType(feature) == "node") {
493     return I18n.t('browse.start_rjs.object_list.type.node');
494   } else if (featureType(feature) == "way") {
495     return I18n.t('browse.start_rjs.object_list.type.way');
496   }
497 }
498
499 function featureName(feature) {
500   var lang = $('html').attr('lang');
501   if (feature.attributes['name:' + lang]) {
502     return feature.attributes['name:' + lang];
503   } else if (feature.attributes.name) {
504     return feature.attributes.name;
505   } else {
506     return feature.osm_id;
507   }
508 }
509
510 function featureNameSelect(feature) {
511   var lang = $('html').attr('lang');
512   if (feature.attributes['name:' + lang]) {
513     return feature.attributes['name:' + lang];
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.selected.type.node", { id: feature.osm_id });
518   } else if (featureType(feature) == "way") {
519     return I18n.t("browse.start_rjs.object_list.selected.type.way", { id: feature.osm_id });
520   }
521 }
522
523 function featureNameHistory(feature) {
524   var lang = $('html').attr('lang');
525   if (feature.attributes['name:' + lang]) {
526     return feature.attributes['name:' + lang];
527   } else if (feature.attributes.name) {
528     return feature.attributes.name;
529   } else if (featureType(feature) == "node") {
530     return I18n.t("browse.start_rjs.object_list.history.type.node", { id: feature.osm_id });
531   } else if (featureType(feature) == "way") {
532     return I18n.t("browse.start_rjs.object_list.history.type.way", { id: feature.osm_id });
533   }
534 }
535
536 function setStatus(status) {
537   $("#browse_status").html(status);
538   $("#browse_status").show();
539 }
540   
541 function clearStatus() {
542   $("#browse_status").html("");
543   $("#browse_status").hide();
544 }
545
546 startBrowse("<%=j render :partial => "sidebar" %>");