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