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