]> git.openstreetmap.org Git - rails.git/blob - app/assets/javascripts/index/browse.js
Update hash on P2 and iD edit pages and throttle
[rails.git] / app / assets / javascripts / index / browse.js
1 //= require templates/browse/feature
2 //= require templates/browse/feature_list
3 //= require templates/browse/feature_history
4
5 function initializeBrowse(map) {
6   var browseBounds;
7   var layersById;
8   var selectedLayer;
9   var browseObjectList;
10   var areasHidden = false;
11   var locationFilter;
12
13   var dataLayer = map.dataLayer;
14
15   dataLayer.setStyle({
16     way: {
17       weight: 3,
18       color: "#000000",
19       opacity: 0.4
20     },
21     area: {
22       weight: 3,
23       color: "#ff0000"
24     },
25     node: {
26       color: "#00ff00"
27     }
28   });
29
30   dataLayer.isWayArea = function () {
31     return !areasHidden && L.OSM.DataLayer.prototype.isWayArea.apply(this, arguments);
32   };
33
34   dataLayer.on("click", function (e) {
35     onSelect(e.layer);
36   });
37
38   map.on('layeradd', function (e) {
39     if (e.layer === dataLayer) {
40       $.ajax({ url: "/browse/start", success: function (sidebarHtml) {
41         startBrowse(sidebarHtml);
42       }});
43     }
44   });
45
46   map.on('layerremove', function (e) {
47     if (e.layer === dataLayer) {
48       closeSidebar();
49     }
50   });
51
52   function startBrowse(sidebarHtml) {
53     locationFilter = new L.LocationFilter({
54       enableButton: false,
55       adjustButton: false
56     }).addTo(map);
57
58     locationFilter.on("change", getData);
59
60     $("#sidebar_title").html(I18n.t('browse.start_rjs.data_frame_title'));
61     $("#sidebar_content").html(sidebarHtml);
62
63     openSidebar();
64
65     if (browseObjectList) loadObjectList();
66
67     map.on("moveend", updateData);
68     updateData();
69
70     $("#browse_filter_toggle").click(toggleFilter);
71
72     $("#browse_hide_areas_box").html(I18n.t('browse.start_rjs.hide_areas'));
73     $("#browse_hide_areas_box").click(toggleAreas);
74
75     $("#sidebar").one("closed", function () {
76       map.removeLayer(dataLayer);
77       map.removeLayer(locationFilter);
78       map.off("moveend", updateData);
79       locationFilter.off("change", getData);
80     });
81   }
82
83   function updateData() {
84     if (!locationFilter.isEnabled()) {
85       if (map.getZoom() >= 15) {
86         var bounds = map.getBounds();
87         if (!browseBounds || !browseBounds.contains(bounds)) {
88           browseBounds = bounds;
89           getData();
90         }
91       } else {
92         setStatus(I18n.t('browse.start_rjs.zoom_or_select'));
93       }
94     }
95   }
96
97   function toggleFilter() {
98     if (locationFilter.isEnabled()) {
99       $("#browse_filter_toggle").html(I18n.t('browse.start_rjs.manually_select'));
100       locationFilter.disable();
101     } else {
102       $("#browse_filter_toggle").html(I18n.t('browse.start_rjs.view_data'));
103       locationFilter.setBounds(map.getBounds().pad(-0.2));
104       locationFilter.enable();
105     }
106
107     getData();
108   }
109
110   function toggleAreas() {
111     if (areasHidden) {
112       $("#browse_hide_areas_box").html(I18n.t('browse.start_rjs.hide_areas'));
113       areasHidden = false;
114     } else {
115       $("#browse_hide_areas_box").html(I18n.t('browse.start_rjs.show_areas'));
116       areasHidden = true;
117     }
118
119     getData();
120   }
121
122   function displayFeatureWarning(count, limit, callback) {
123     clearStatus();
124
125     var div = document.createElement("div");
126
127     var p = document.createElement("p");
128     p.appendChild(document.createTextNode(I18n.t("browse.start_rjs.loaded_an_area_with_num_features", { num_features: count, max_features: limit })));
129     div.appendChild(p);
130
131     var input = document.createElement("input");
132     input.type = "submit";
133     input.value = I18n.t('browse.start_rjs.load_data');
134     input.onclick = callback;
135     div.appendChild(input);
136
137     $("#browse_content").html("");
138     $("#browse_content").append(div);
139   }
140
141   var dataLoader;
142
143   function getData() {
144     var bounds = locationFilter.isEnabled() ? locationFilter.getBounds() : map.getBounds();
145     var size = bounds.getSize();
146
147     if (size > OSM.MAX_REQUEST_AREA) {
148       setStatus(I18n.t("browse.start_rjs.unable_to_load_size", { max_bbox_size: OSM.MAX_REQUEST_AREA, bbox_size: size }));
149       return;
150     }
151
152     setStatus(I18n.t('browse.start_rjs.loading'));
153
154     var url = "/api/" + OSM.API_VERSION + "/map?bbox=" + bounds.toBBoxString();
155
156     /*
157      * Modern browsers are quite happy showing far more than 100 features in
158      * the data browser, so increase the limit to 2000 by default, but keep
159      * it restricted to 500 for IE8 and 100 for older IEs.
160      */
161     var maxFeatures = 2000;
162
163     /*@cc_on
164       if (navigator.appVersion < 8) {
165         maxFeatures = 100;
166       } else if (navigator.appVersion < 9) {
167         maxFeatures = 500;
168       }
169     @*/
170
171     if (dataLoader) dataLoader.abort();
172
173     dataLoader = $.ajax({
174       url: url,
175       success: function (xml) {
176         clearStatus();
177
178         $("#browse_content").empty();
179         dataLayer.clearLayers();
180         selectedLayer = null;
181
182         var features = dataLayer.buildFeatures(xml);
183
184         function addFeatures() {
185           dataLayer.addData(features);
186
187           layersById = {};
188
189           dataLayer.eachLayer(function (layer) {
190             var feature = layer.feature;
191             layersById[feature.id] = layer;
192             $.extend(feature, {
193               typeName: featureTypeName(feature),
194               url: "/browse/" + feature.type + "/" + feature.id,
195               name: featureName(feature)
196             });
197           });
198
199           browseObjectList = $(JST["templates/browse/feature_list"]({
200             features: features,
201             url: url
202           }))[0];
203
204           loadObjectList();
205         }
206
207         if (features.length < maxFeatures) {
208           addFeatures();
209         } else {
210           displayFeatureWarning(features.length, maxFeatures, addFeatures);
211         }
212
213         dataLoader = null;
214       }
215     });
216   }
217
218   function viewFeatureLink() {
219     var layer = layersById[$(this).data("feature-id")];
220
221     onSelect(layer);
222
223     if (locationFilter.isEnabled()) {
224       map.panTo(layer.getBounds().getCenter());
225     }
226
227     return false;
228   }
229
230   function loadObjectList() {
231     $("#browse_content").html(browseObjectList);
232     $("#browse_content").find("a[data-feature-id]").click(viewFeatureLink);
233
234     return false;
235   }
236
237   function onSelect(layer) {
238     // Unselect previously selected feature
239     if (selectedLayer) {
240       selectedLayer.setStyle(selectedLayer.originalStyle);
241     }
242
243     // Redraw in selected style
244     layer.originalStyle = layer.options;
245     layer.setStyle({color: '#0000ff', weight: 8});
246
247     // If the current object is the list, don't innerHTML="", since that could clear it.
248     if ($("#browse_content").firstChild == browseObjectList) {
249       $("#browse_content").removeChild(browseObjectList);
250     } else {
251       $("#browse_content").empty();
252     }
253
254     var feature = layer.feature;
255
256     $("#browse_content").html(JST["templates/browse/feature"]({
257       name: featureNameSelect(feature),
258       url: "/browse/" + feature.type + "/" + feature.id,
259       attributes: feature.tags
260     }));
261
262     $("#browse_content").find("a.browse_show_list").click(loadObjectList);
263     $("#browse_content").find("a.browse_show_history").click(loadHistory);
264
265     // Stash the currently drawn feature
266     selectedLayer = layer;
267   }
268
269   function loadHistory() {
270     $(this).attr("href", "").text(I18n.t('browse.start_rjs.wait'));
271
272     var feature = selectedLayer.feature;
273
274     $.ajax({
275       url: "/api/" + OSM.API_VERSION + "/" + feature.type + "/" + feature.id + "/history",
276       success: function (xml) {
277         if (selectedLayer.feature != feature || $("#browse_content").firstChild == browseObjectList) {
278           return;
279         }
280
281         $(this).remove();
282
283         var history = [];
284         var nodes = xml.getElementsByTagName(feature.type);
285         for (var i = nodes.length - 1; i >= 0; i--) {
286           history.push({
287             user: nodes[i].getAttribute("user") || I18n.t('browse.start_rjs.private_user'),
288             timestamp: nodes[i].getAttribute("timestamp")
289           });
290         }
291
292         $("#browse_content").append(JST["templates/browse/feature_history"]({
293           name: featureNameHistory(feature),
294           url: "/browse/" + feature.type + "/" + feature.id,
295           history: history
296         }));
297       }.bind(this)
298     });
299
300     return false;
301   }
302
303   function featureTypeName(feature) {
304     return I18n.t('browse.start_rjs.object_list.type.' + feature.type);
305   }
306
307   function featureName(feature) {
308     return feature.tags['name:' + $('html').attr('lang')] ||
309       feature.tags.name ||
310       feature.id;
311   }
312
313   function featureNameSelect(feature) {
314     return feature.tags['name:' + $('html').attr('lang')] ||
315       feature.tags.name ||
316       I18n.t("browse.start_rjs.object_list.selected.type." + feature.type, { id: feature.id });
317   }
318
319   function featureNameHistory(feature) {
320     return feature.tags['name:' + $('html').attr('lang')] ||
321       feature.tags.name ||
322       I18n.t("browse.start_rjs.object_list.history.type." + feature.type, { id: feature.id });
323   }
324
325   function setStatus(status) {
326     $("#browse_status").html(status);
327     $("#browse_status").show();
328   }
329
330   function clearStatus() {
331     $("#browse_status").html("");
332     $("#browse_status").hide();
333   }
334 }