Module: Mapkick::Helper
- Defined in:
- lib/mapkick/helper.rb
Instance Method Summary collapse
-
#js_map(data_source, **options) ⇒ Object
don’t break out options since need to merge with default options.
Instance Method Details
#js_map(data_source, **options) ⇒ Object
don’t break out options since need to merge with default options
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 |
# File 'lib/mapkick/helper.rb', line 4 def js_map(data_source, **) = Mapkick::Utils.deep_merge(Mapkick., ) @mapkick_map_id ||= 0 element_id = .delete(:id) || "map-#{@mapkick_map_id += 1}" height = (.delete(:height) || "500px").to_s width = (.delete(:width) || "100%").to_s nonce = .fetch(:nonce, true) .delete(:nonce) if nonce == true # Secure Headers also defines content_security_policy_nonce but it takes an argument # Rails 5.2 overrides this method, but earlier versions do not if respond_to?(:content_security_policy_nonce) && (content_security_policy_nonce rescue nil) # Rails 5.2+ nonce = content_security_policy_nonce elsif respond_to?(:content_security_policy_script_nonce) # Secure Headers nonce = content_security_policy_script_nonce else nonce = nil end end nonce_html = nonce ? " nonce=\"#{ERB::Util.html_escape(nonce)}\"" : nil # html vars html_vars = { id: element_id, height: height, width: width, # don't delete loading option since it needs to be passed to JS loading: [:loading] || "Loading..." } [:height, :width].each do |k| # limit to alphanumeric and % for simplicity # this prevents things like calc() but safety is the priority # dot does not need escaped in square brackets raise ArgumentError, "Invalid #{k}" unless html_vars[k] =~ /\A[a-zA-Z0-9%.]*\z/ end html_vars.each_key do |k| # escape all variables # we already limit height and width above, but escape for safety as fail-safe # to prevent XSS injection in worse-case scenario html_vars[k] = ERB::Util.html_escape(html_vars[k]) end html = %(<div id="%{id}" style="height: %{height}; width: %{width};"><div style="height: %{height}; text-align: center; color: #999; line-height: %{height}; font-size: 14px; font-family: 'Lucida Grande', 'Lucida Sans Unicode', Verdana, Arial, Helvetica, sans-serif;">%{loading}</div></div>) % html_vars # access token access_token = .delete(:access_token) || .delete(:accessToken) || ENV["MAPBOX_ACCESS_TOKEN"] if access_token # can bypass with string keys # but should help prevent common errors if access_token.start_with?("sk.") raise Mapkick::Error, "Expected public access token" elsif !access_token.start_with?("pk.") raise Mapkick::Error, "Invalid access token" end [:accessToken] = access_token end # js vars js_vars = { id: element_id, data: data_source, options: } js_vars.each_key do |k| js_vars[k] = Mapkick::Utils.json_escape(js_vars[k].to_json) end createjs = "new Mapkick.Map(%{id}, %{data}, %{options});" % js_vars # don't rerun JS on preview js = " <script\#{nonce_html}>\n (function() {\n if (document.documentElement.hasAttribute(\"data-turbolinks-preview\")) return;\n if (document.documentElement.hasAttribute(\"data-turbo-preview\")) return;\n\n var createMap = function() { \#{createjs} };\n if (\"Mapkick\" in window) {\n createMap();\n } else {\n window.addEventListener(\"mapkick:load\", createMap, true);\n }\n })();\n </script>\n JS\n\n html += \"\\n\#{js}\"\n\n html.respond_to?(:html_safe) ? html.html_safe : html\nend\n" |