]> git.openstreetmap.org Git - rails.git/blob - app/assets/javascripts/leaflet.share.js
Use the bootstrap spacer variable as the basis for spacing calcuation, and match...
[rails.git] / app / assets / javascripts / leaflet.share.js
1 L.OSM.share = function (options) {
2   var control = L.control(options),
3       marker = L.marker([0, 0], { draggable: true }),
4       locationFilter = new L.LocationFilter({
5         enableButton: false,
6         adjustButton: false
7       });
8
9   control.onAdd = function (map) {
10     var $container = $("<div>")
11       .attr("class", "control-share");
12
13     var button = $("<a>")
14       .attr("class", "control-button")
15       .attr("href", "#")
16       .attr("title", I18n.t("javascripts.share.title"))
17       .html("<span class=\"icon share\"></span>")
18       .on("click", toggle)
19       .appendTo($container);
20
21     var $ui = $("<div>")
22       .attr("class", "share-ui");
23
24     $("<div>")
25       .attr("class", "sidebar_heading")
26       .appendTo($ui)
27       .append(
28         $("<span>")
29           .text(I18n.t("javascripts.close"))
30           .attr("class", "icon close")
31           .bind("click", toggle))
32       .append(
33         $("<h4>")
34           .text(I18n.t("javascripts.share.title")));
35
36     // Link / Embed
37
38     var $linkSection = $("<div>")
39       .attr("class", "section share-link")
40       .appendTo($ui);
41
42     $("<h4>")
43       .text(I18n.t("javascripts.share.link"))
44       .appendTo($linkSection);
45
46     var $form = $("<form>")
47       .attr("class", "standard-form")
48       .appendTo($linkSection);
49
50     $("<div>")
51       .attr("class", "standard-form-row")
52       .appendTo($form)
53       .append(
54         $("<label>")
55           .attr("for", "link_marker")
56           .append(
57             $("<input>")
58               .attr("id", "link_marker")
59               .attr("type", "checkbox")
60               .bind("change", toggleMarker))
61           .append(I18n.t("javascripts.share.include_marker")));
62
63     $("<div>")
64       .attr("class", "share-tabs")
65       .appendTo($form)
66       .append($("<a>")
67         .attr("class", "active")
68         .attr("for", "long_input")
69         .attr("id", "long_link")
70         .text(I18n.t("javascripts.share.long_link")))
71       .append($("<a>")
72         .attr("for", "short_input")
73         .attr("id", "short_link")
74         .text(I18n.t("javascripts.share.short_link")))
75       .append($("<a>")
76         .attr("for", "embed_html")
77         .attr("href", "#")
78         .text(I18n.t("javascripts.share.embed")))
79       .on("click", "a", function (e) {
80         e.preventDefault();
81         var id = "#" + $(this).attr("for");
82         $linkSection.find(".share-tabs a")
83           .removeClass("active");
84         $(this).addClass("active");
85         $linkSection.find(".share-tab")
86           .hide();
87         $linkSection.find(".share-tab:has(" + id + ")")
88           .show()
89           .find("input, textarea")
90           .select();
91       });
92
93     $("<div>")
94       .attr("class", "standard-form-row share-tab")
95       .css("display", "block")
96       .appendTo($form)
97       .append($("<input>")
98         .attr("id", "long_input")
99         .attr("type", "text")
100         .on("click", select));
101
102     $("<div>")
103       .attr("class", "standard-form-row share-tab")
104       .appendTo($form)
105       .append($("<input>")
106         .attr("id", "short_input")
107         .attr("type", "text")
108         .on("click", select));
109
110     $("<div>")
111       .attr("class", "standard-form-row share-tab")
112       .appendTo($form)
113       .append(
114         $("<textarea>")
115           .attr("id", "embed_html")
116           .on("click", select))
117       .append(
118         $("<p>")
119           .attr("class", "text-muted")
120           .text(I18n.t("javascripts.share.paste_html"))
121           .appendTo($linkSection));
122
123     // Geo URI
124
125     var $geoUriSection = $("<div>")
126       .attr("class", "section share-geo-uri")
127       .appendTo($ui);
128
129     $("<h4>")
130       .text(I18n.t("javascripts.share.geo_uri"))
131       .appendTo($geoUriSection);
132
133     $("<div>")
134       .appendTo($geoUriSection)
135       .append($("<a>")
136         .attr("id", "geo_uri"));
137
138     // Image
139
140     var $imageSection = $("<div>")
141       .attr("class", "section share-image")
142       .appendTo($ui);
143
144     $("<h4>")
145       .text(I18n.t("javascripts.share.image"))
146       .appendTo($imageSection);
147
148     $("<div>")
149       .attr("id", "export-warning")
150       .attr("class", "text-muted")
151       .text(I18n.t("javascripts.share.only_standard_layer"))
152       .appendTo($imageSection);
153
154     $form = $("<form>")
155       .attr("id", "export-image")
156       .attr("class", "standard-form")
157       .attr("action", "/export/finish")
158       .attr("method", "post")
159       .appendTo($imageSection);
160
161     $("<div>")
162       .attr("class", "standard-form-row")
163       .appendTo($form)
164       .append(
165         $("<label>")
166           .attr("for", "image_filter")
167           .append(
168             $("<input>")
169               .attr("id", "image_filter")
170               .attr("type", "checkbox")
171               .bind("change", toggleFilter))
172           .append(I18n.t("javascripts.share.custom_dimensions")));
173
174     $("<div>")
175       .attr("class", "standard-form-row")
176       .appendTo($form)
177       .append(
178         $("<label>")
179           .attr("for", "mapnik_format")
180           .text(I18n.t("javascripts.share.format")))
181       .append($("<select>")
182         .attr("name", "mapnik_format")
183         .attr("id", "mapnik_format")
184         .append($("<option>").val("png").text("PNG").prop("selected", true))
185         .append($("<option>").val("jpeg").text("JPEG"))
186         .append($("<option>").val("svg").text("SVG"))
187         .append($("<option>").val("pdf").text("PDF")));
188
189     $("<div>")
190       .attr("class", "standard-form-row")
191       .appendTo($form)
192       .append($("<label>")
193         .attr("for", "mapnik_scale")
194         .text(I18n.t("javascripts.share.scale")))
195       .append("1 : ")
196       .append($("<input>")
197         .attr("name", "mapnik_scale")
198         .attr("id", "mapnik_scale")
199         .attr("type", "text")
200         .on("change", update));
201
202     ["minlon", "minlat", "maxlon", "maxlat"].forEach(function (name) {
203       $("<input>")
204         .attr("id", "mapnik_" + name)
205         .attr("name", name)
206         .attr("type", "hidden")
207         .appendTo($form);
208     });
209
210     $("<input>")
211       .attr("name", "format")
212       .attr("value", "mapnik")
213       .attr("type", "hidden")
214       .appendTo($form);
215
216     var csrf_param = $("meta[name=csrf-param]").attr("content"),
217         csrf_token = $("meta[name=csrf-token]").attr("content");
218
219     $("<input>")
220       .attr("name", csrf_param)
221       .attr("value", csrf_token)
222       .attr("type", "hidden")
223       .appendTo($form);
224
225     var args = {
226       width: "<span id=\"mapnik_image_width\"></span>",
227       height: "<span id=\"mapnik_image_height\"></span>"
228     };
229
230     $("<p>")
231       .attr("class", "text-muted")
232       .html(I18n.t("javascripts.share.image_dimensions", args))
233       .appendTo($form);
234
235     $("<input>")
236       .attr("type", "submit")
237       .attr("value", I18n.t("javascripts.share.download"))
238       .appendTo($form);
239
240     locationFilter
241       .on("change", update)
242       .addTo(map);
243
244     marker.on("dragend", movedMarker);
245     map.on("move", movedMap);
246     map.on("moveend layeradd layerremove", update);
247
248     options.sidebar.addPane($ui);
249
250     $ui
251       .on("hide", hidden);
252
253     function hidden() {
254       map.removeLayer(marker);
255       map.options.scrollWheelZoom = map.options.doubleClickZoom = true;
256       locationFilter.disable();
257       update();
258     }
259
260     function toggle(e) {
261       e.stopPropagation();
262       e.preventDefault();
263
264       $("#mapnik_scale").val(getScale());
265       marker.setLatLng(map.getCenter());
266
267       update();
268       options.sidebar.togglePane($ui, button);
269       $(".leaflet-control .control-button").tooltip("hide");
270     }
271
272     function toggleMarker() {
273       if ($(this).is(":checked")) {
274         marker.setLatLng(map.getCenter());
275         map.addLayer(marker);
276         map.options.scrollWheelZoom = map.options.doubleClickZoom = "center";
277       } else {
278         map.removeLayer(marker);
279         map.options.scrollWheelZoom = map.options.doubleClickZoom = true;
280       }
281       update();
282     }
283
284     function toggleFilter() {
285       if ($(this).is(":checked")) {
286         locationFilter.setBounds(map.getBounds().pad(-0.2));
287         locationFilter.enable();
288       } else {
289         locationFilter.disable();
290       }
291       update();
292     }
293
294     function movedMap() {
295       marker.setLatLng(map.getCenter());
296       update();
297     }
298
299     function movedMarker() {
300       if (map.hasLayer(marker)) {
301         map.off("move", movedMap);
302         map.on("moveend", updateOnce);
303         map.panTo(marker.getLatLng());
304       }
305     }
306
307     function updateOnce() {
308       map.off("moveend", updateOnce);
309       map.on("move", movedMap);
310       update();
311     }
312
313     function escapeHTML(string) {
314       var htmlEscapes = {
315         "&": "&amp;",
316         "<": "&lt;",
317         ">": "&gt;",
318         "\"": "&quot;",
319         "'": "&#x27;"
320       };
321       return string === null ? "" : String(string).replace(/[&<>"']/g, function (match) {
322         return htmlEscapes[match];
323       });
324     }
325
326     function update() {
327       var bounds = map.getBounds();
328
329       $("#link_marker")
330         .prop("checked", map.hasLayer(marker));
331
332       $("#image_filter")
333         .prop("checked", locationFilter.isEnabled());
334
335       // Link / Embed
336
337       $("#short_input").val(map.getShortUrl(marker));
338       $("#long_input").val(map.getUrl(marker));
339       $("#short_link").attr("href", map.getShortUrl(marker));
340       $("#long_link").attr("href", map.getUrl(marker));
341
342       var params = {
343         bbox: bounds.toBBoxString(),
344         layer: map.getMapBaseLayerId()
345       };
346
347       if (map.hasLayer(marker)) {
348         var latLng = marker.getLatLng().wrap();
349         params.marker = latLng.lat + "," + latLng.lng;
350       }
351
352       $("#embed_html").val(
353         "<iframe width=\"425\" height=\"350\" frameborder=\"0\" scrolling=\"no\" marginheight=\"0\" marginwidth=\"0\" src=\"" +
354           escapeHTML(OSM.SERVER_PROTOCOL + "://" + OSM.SERVER_URL + "/export/embed.html?" + $.param(params)) +
355           "\" style=\"border: 1px solid black\"></iframe><br/>" +
356           "<small><a href=\"" + escapeHTML(map.getUrl(marker)) + "\">" +
357           escapeHTML(I18n.t("javascripts.share.view_larger_map")) + "</a></small>");
358
359       // Geo URI
360
361       $("#geo_uri")
362         .attr("href", map.getGeoUri(marker))
363         .html(map.getGeoUri(marker));
364
365       // Image
366
367       if (locationFilter.isEnabled()) {
368         bounds = locationFilter.getBounds();
369       }
370
371       var scale = $("#mapnik_scale").val(),
372           size = L.bounds(L.CRS.EPSG3857.project(bounds.getSouthWest()),
373                           L.CRS.EPSG3857.project(bounds.getNorthEast())).getSize(),
374           maxScale = Math.floor(Math.sqrt(size.x * size.y / 0.3136));
375
376       $("#mapnik_minlon").val(bounds.getWest());
377       $("#mapnik_minlat").val(bounds.getSouth());
378       $("#mapnik_maxlon").val(bounds.getEast());
379       $("#mapnik_maxlat").val(bounds.getNorth());
380
381       if (scale < maxScale) {
382         scale = roundScale(maxScale);
383         $("#mapnik_scale").val(scale);
384       }
385
386       $("#mapnik_image_width").text(Math.round(size.x / scale / 0.00028));
387       $("#mapnik_image_height").text(Math.round(size.y / scale / 0.00028));
388
389       if (map.getMapBaseLayerId() === "mapnik") {
390         $("#export-image").show();
391         $("#export-warning").hide();
392       } else {
393         $("#export-image").hide();
394         $("#export-warning").show();
395       }
396     }
397
398     function select() {
399       $(this).select();
400     }
401
402     function getScale() {
403       var bounds = map.getBounds(),
404           centerLat = bounds.getCenter().lat,
405           halfWorldMeters = 6378137 * Math.PI * Math.cos(centerLat * Math.PI / 180),
406           meters = halfWorldMeters * (bounds.getEast() - bounds.getWest()) / 180,
407           pixelsPerMeter = map.getSize().x / meters,
408           metersPerPixel = 1 / (92 * 39.3701);
409       return Math.round(1 / (pixelsPerMeter * metersPerPixel));
410     }
411
412     function roundScale(scale) {
413       var precision = 5 * Math.pow(10, Math.floor(Math.LOG10E * Math.log(scale)) - 2);
414       return precision * Math.ceil(scale / precision);
415     }
416
417     return $container[0];
418   };
419
420   return control;
421 };