]> git.openstreetmap.org Git - rails.git/blob - app/assets/javascripts/index.js
Fix feedback loop between L.hash and popstate
[rails.git] / app / assets / javascripts / index.js
1 //= require_self
2 //= require leaflet.sidebar
3 //= require leaflet.locate
4 //= require leaflet.layers
5 //= require leaflet.key
6 //= require leaflet.note
7 //= require leaflet.share
8 //= require index/search
9 //= require index/browse
10 //= require index/export
11 //= require index/notes
12 //= require index/history
13 //= require router
14
15 $(document).ready(function () {
16   var params = OSM.mapParams();
17
18   var map = L.map("map", {
19     zoomControl: false,
20     layerControl: false
21   });
22
23   map.attributionControl.setPrefix('');
24
25   map.hash = L.hash(map);
26
27   $(window).on('popstate', function(e) {
28     // popstate is triggered when the hash changes as well as on actual navigation
29     // events. We want to update the hash on the latter and not the former.
30     if (e.originalEvent.state) {
31       map.hash.update();
32     }
33   });
34
35   var copyright = I18n.t('javascripts.map.copyright', {copyright_url: '/copyright'});
36
37   var layers = [
38     new L.OSM.Mapnik({
39       attribution: copyright,
40       code: "M",
41       keyid: "mapnik",
42       name: I18n.t("javascripts.map.base.standard")
43     }),
44     new L.OSM.CycleMap({
45       attribution: copyright + ". Tiles courtesy of <a href='http://www.opencyclemap.org/' target='_blank'>Andy Allan</a>",
46       code: "C",
47       keyid: "cyclemap",
48       name: I18n.t("javascripts.map.base.cycle_map")
49     }),
50     new L.OSM.TransportMap({
51       attribution: copyright + ". Tiles courtesy of <a href='http://www.opencyclemap.org/' target='_blank'>Andy Allan</a>",
52       code: "T",
53       keyid: "transportmap",
54       name: I18n.t("javascripts.map.base.transport_map")
55     }),
56     new L.OSM.MapQuestOpen({
57       attribution: copyright + ". Tiles courtesy of <a href='http://www.mapquest.com/' target='_blank'>MapQuest</a> <img src='http://developer.mapquest.com/content/osm/mq_logo.png'>",
58       code: "Q",
59       keyid: "mapquest",
60       name: I18n.t("javascripts.map.base.mapquest")
61     }),
62     new L.OSM.HOT({
63       attribution: copyright + ". Tiles courtesy of <a href='http://hot.openstreetmap.org/' target='_blank'>Humanitarian OpenStreetMap Team</a>",
64       code: "H",
65       keyid: "hot",
66       name: I18n.t("javascripts.map.base.hot")
67     })
68   ];
69
70   function updateLayers(params) {
71     var layerParam = params.layers || "M";
72     var layersAdded = "";
73
74     for (var i = layers.length - 1; i >= 0; i--) {
75       if (layerParam.indexOf(layers[i].options.code) >= 0) {
76         map.addLayer(layers[i]);
77         layersAdded = layersAdded + layers[i].options.code;
78       } else if (i == 0 && layersAdded == "") {
79         map.addLayer(layers[i]);
80       } else {
81         map.removeLayer(layers[i]);
82       }
83     }
84   }
85
86   updateLayers(params);
87
88   $(window).on("hashchange", function () {
89     updateLayers(OSM.mapParams());
90   });
91
92   map.on("baselayerchange", function (e) {
93     if (map.getZoom() > e.layer.options.maxZoom) {
94       map.setView(map.getCenter(), e.layer.options.maxZoom, { reset: true });
95     }
96   });
97
98   map.noteLayer = new L.LayerGroup();
99   map.noteLayer.options = {code: 'N'};
100
101   map.dataLayer = new L.OSM.DataLayer(null);
102   map.dataLayer.options.code = 'D';
103
104   if (OSM.STATUS != 'api_offline' && OSM.STATUS != 'database_offline') {
105     if (params.layers.indexOf(map.noteLayer.options.code) >= 0) {
106       map.addLayer(map.noteLayer);
107     }
108
109     if (params.layers.indexOf(map.dataLayer.options.code) >= 0) {
110       map.addLayer(map.dataLayer);
111     }
112   }
113
114   var position = $('html').attr('dir') === 'rtl' ? 'topleft' : 'topright';
115
116   L.OSM.zoom({position: position})
117     .addTo(map);
118
119   L.control.locate({
120     position: position,
121     strings: {
122       title: I18n.t('javascripts.map.locate.title'),
123       popup: I18n.t('javascripts.map.locate.popup')
124     }
125   }).addTo(map);
126
127   var sidebar = L.OSM.sidebar('#map-ui')
128     .addTo(map);
129
130   L.OSM.layers({
131     position: position,
132     layers: layers,
133     sidebar: sidebar
134   }).addTo(map);
135
136   L.OSM.key({
137     position: position,
138     sidebar: sidebar
139   }).addTo(map);
140
141   L.OSM.share({
142     position: position,
143     sidebar: sidebar,
144     short: true
145   }).addTo(map);
146
147   L.OSM.note({
148     position: position,
149     sidebar: sidebar
150   }).addTo(map);
151
152   L.control.scale()
153     .addTo(map);
154
155   $('.leaflet-control .control-button').tooltip({placement: 'left', container: 'body'});
156
157   map.on('moveend layeradd layerremove', function() {
158     updatelinks(
159       map.getCenter().wrap(),
160       map.getZoom(),
161       map.getLayersCode(),
162       map._object);
163
164     var expiry = new Date();
165     expiry.setYear(expiry.getFullYear() + 10);
166     $.cookie("_osm_location", cookieContent(map), { expires: expiry });
167
168     // Trigger hash update on layer changes.
169     map.hash.onMapMove();
170   });
171
172   if (OSM.PIWIK) {
173     map.on('layeradd', function (e) {
174       if (e.layer.options) {
175         var goal = OSM.PIWIK.goals[e.layer.options.keyid];
176
177         if (goal) {
178           $('body').trigger('piwikgoal', goal);
179         }
180       }
181     });
182   }
183
184   if (params.bounds) {
185     map.fitBounds(params.bounds);
186   } else {
187     map.setView([params.lat, params.lon], params.zoom);
188   }
189
190   var marker = L.marker([0, 0], {icon: getUserIcon()});
191
192   if (params.marker) {
193     marker.setLatLng([params.mlat, params.mlon]).addTo(map);
194   }
195
196   $("#homeanchor").on("click", function(e) {
197     e.preventDefault();
198
199     var data = $(this).data(),
200       center = L.latLng(data.lat, data.lon);
201
202     map.setView(center, data.zoom);
203     marker.setLatLng(center).addTo(map);
204   });
205
206   $("a[data-editor=remote]").click(function(e) {
207       remoteEditHandler(map.getBounds());
208       e.preventDefault();
209   });
210
211   if (OSM.preferred_editor == "remote" && $('body').hasClass("site-edit")) {
212     remoteEditHandler(map.getBounds());
213   }
214
215   if (OSM.params().edit_help) {
216     $('#editanchor')
217       .removeAttr('title')
218       .tooltip({
219         placement: 'bottom',
220         title: I18n.t('javascripts.edit_help')
221       })
222       .tooltip('show');
223
224     $('body').one('click', function() {
225       $('#editanchor').tooltip('hide');
226     });
227   }
228
229   initializeBrowse(map);
230   initializeNotes(map);
231
232   OSM.Index = function(map) {
233     var page = {}, minimized = false;
234
235     page.pushstate = page.popstate = function(path) {
236       if (minimized) $("#sidebar").addClass("minimized");
237       map.invalidateSize();
238       $("#view_tab").addClass("current");
239       $('#sidebar_content').load(path);
240     };
241
242     page.unload = function() {
243       $("#view_tab").removeClass("current");
244     };
245
246     page.minimizeSidebar = function() {
247       $("#sidebar").addClass("minimized");
248       map.invalidateSize();
249       minimized = true;
250     };
251
252     $(document).on("click", "#sidebar_content .close", page.minimizeSidebar);
253
254     return page;
255   };
256
257   OSM.Browse = function(map) {
258     var page = {};
259
260     page.pushstate = page.popstate = function(path, type, id) {
261       $("#sidebar").removeClass("minimized");
262       map.invalidateSize();
263       $('#sidebar_content').load(path, function() {
264         page.load(path, type, id);
265       });
266     };
267
268     page.load = function(path, type, id) {
269       if (OSM.STATUS === 'api_offline' || OSM.STATUS === 'database_offline') return;
270
271       if (type === 'note') {
272         map.noteLayer.showNote(parseInt(id));
273       } else {
274         map.addObject({type: type, id: parseInt(id)}, {zoom: true});
275       }
276     };
277
278     page.unload = function() {
279       map.removeObject();
280     };
281
282     return page;
283   };
284
285   var history = OSM.History(map);
286
287   OSM.route = OSM.Router({
288     "/":                           OSM.Index(map),
289     "/search":                     OSM.Search(map),
290     "/export":                     OSM.Export(map),
291     "/history":                    history,
292     "/user/:display_name/edits":   history,
293     "/browse/friends":             history,
294     "/browse/nearby":              history,
295     "/browse/:type/:id(/history)": OSM.Browse(map)
296   });
297
298   $(document).on("click", "a", function(e) {
299     if (e.isDefaultPrevented() || e.isPropagationStopped()) return;
300     if (this.host === window.location.host && OSM.route(this.pathname + this.search + this.hash)) e.preventDefault();
301   });
302
303   $("#search_form").on("submit", function(e) {
304     e.preventDefault();
305     OSM.route("/search?query=" + encodeURIComponent($("#query").val()) + OSM.formatHash(map));
306   });
307
308   $("#describe_location").on("click", function(e) {
309     e.preventDefault();
310     var precision = zoomPrecision(map.getZoom());
311     OSM.route("/search?query=" + encodeURIComponent(
312       map.getCenter().lat.toFixed(precision) + "," +
313       map.getCenter().lng.toFixed(precision)));
314   });
315
316 });