{"id":110,"date":"2026-02-23T18:06:22","date_gmt":"2026-02-23T18:06:22","guid":{"rendered":"https:\/\/zh2o.ch\/?page_id=110"},"modified":"2026-04-07T11:51:59","modified_gmt":"2026-04-07T11:51:59","slug":"locations","status":"publish","type":"page","link":"https:\/\/zh2o.ch\/?page_id=110","title":{"rendered":"Locations"},"content":{"rendered":"    <div id=\"zjm-map-1\"\n         style=\"width:100%;height:500px;\"\n         aria-label=\"Zurich Jump Spots Map\">\n    <\/div>\n\n    <script>\n    function initJumpMap() {\n        var mapEl = document.getElementById(\"zjm-map-1\");\n        if (!mapEl) return;\n\n        var map = new google.maps.Map(mapEl, {\n            zoom: 12,\n            center: { lat: 47.3769, lng: 8.5417 }\n        });\n\n        mapEl.__gjsmap__ = map;\n\n        var spots      = [{\"title\":\"Dynamo\",\"lat\":47.382617,\"lng\":8.539769,\"media_html\":\"\",\"desc\":\"Jumping Spot\\r\\n~3-4m\"},{\"title\":\"Hallenbad Altstetten\",\"lat\":47.38861,\"lng\":8.479595,\"media_html\":\"\\u003Ca href=\\u0022https:\\\/\\\/zh2o.ch\\\/wp-content\\\/uploads\\\/2026\\\/03\\\/WhatsApp-Image-2026-03-09-at-14.10.01.jpeg\\u0022 target=\\u0022_blank\\u0022 rel=\\u0022noopener noreferrer\\u0022\\u003E\\u003Cimg src=\\u0022https:\\\/\\\/zh2o.ch\\\/wp-content\\\/uploads\\\/2026\\\/03\\\/WhatsApp-Image-2026-03-09-at-14.10.01-225x300.jpeg\\u0022 style=\\u0022max-width:220px;display:block;margin:0 0 8px;border-radius:4px;\\u0022\\u003E\\u003C\\\/a\\u003E\",\"desc\":\"Open Diving Tower times:\\r\\nMonday: 07:00\\u201309:00, 13:00\\u201318:00\\r\\nTuesday: 07:00\\u201312:00, 13:00\\u201321:00\\r\\nWednesday: 07:00\\u201312:00, 13:00\\u201318:00, 19:00\\u201321:00\\r\\nThursday: 07:00\\u201312:00, 14:00\\u201318:30, 19:00\\u201321:00\\r\\nFriday: 07:00\\u201321:00\\r\\nSaturday: 07:00\\u201318:00\\r\\nSunday: 07:00\\u201318:0\"},{\"title\":\"Hallenbad Oerlikon\",\"lat\":47.410374,\"lng\":8.556333,\"media_html\":\"\",\"desc\":\"Hallenbad Oerlikon\"},{\"title\":\"Oberer Letten - Kornhausbruecke\",\"lat\":47.385632,\"lng\":8.534497,\"media_html\":\"\",\"desc\":\"~ 10m Jump\"},{\"title\":\"Rote Fabrik\",\"lat\":47.344418,\"lng\":8.537036,\"media_html\":\"\",\"desc\":\"Crane Rope Swing\\r\\n4m and 10m Jump\"},{\"title\":\"Unterer Letten - Viaduktbruecke\",\"lat\":47.3883,\"lng\":8.530178,\"media_html\":\"\\u003Ca href=\\u0022https:\\\/\\\/zh2o.ch\\\/wp-content\\\/uploads\\\/2026\\\/03\\\/viadukt-scaled.jpeg\\u0022 target=\\u0022_blank\\u0022 rel=\\u0022noopener noreferrer\\u0022\\u003E\\u003Cimg src=\\u0022https:\\\/\\\/zh2o.ch\\\/wp-content\\\/uploads\\\/2026\\\/03\\\/viadukt-300x225.jpeg\\u0022 style=\\u0022max-width:220px;display:block;margin:0 0 8px;border-radius:4px;\\u0022\\u003E\\u003C\\\/a\\u003E\",\"desc\":\"Von der Viaduktbruecke kann man springen.\\r\\nHat auch eine Swing.\\r\\nCirca 10m Hoehe.\"}];\n        var openWindow = null;\n\n        var pinSvg = [\n            '<svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"48\" height=\"64\" viewBox=\"0 0 48 64\">',\n            '  <defs>',\n            '    <filter id=\"zjm-shadow\" x=\"-30%\" y=\"-20%\" width=\"160%\" height=\"160%\">',\n            '      <feDropShadow dx=\"0\" dy=\"3\" stdDeviation=\"3\" flood-color=\"#00000044\"\/>',\n            '    <\/filter>',\n            '  <\/defs>',\n            '  <path d=\"M24 2 C11 2 2 11 2 22 C2 36 24 62 24 62 C24 62 46 36 46 22 C46 11 37 2 24 2Z\"',\n            '        fill=\"#0077CC\" filter=\"url(#zjm-shadow)\"\/>',\n            '  <circle cx=\"24\" cy=\"22\" r=\"14\" fill=\"#005FAD\"\/>',\n            '  <path d=\"M24 10 C24 10 15 20 15 26 C15 31 19 35 24 35 C29 35 33 31 33 26 C33 20 24 10 24 10Z\"',\n            '        fill=\"#ffffff\"\/>',\n            '  <ellipse cx=\"20.5\" cy=\"22\" rx=\"2\" ry=\"3.5\" fill=\"#ffffffaa\" transform=\"rotate(-20 20.5 22)\"\/>',\n            '<\/svg>'\n        ].join('');\n\n        var pinUrl  = 'data:image\/svg+xml;charset=UTF-8,' + encodeURIComponent(pinSvg);\n        var pinIcon = {\n            url: pinUrl,\n            scaledSize: new google.maps.Size(48, 64),\n            anchor: new google.maps.Point(24, 64)\n        };\n\n        spots.forEach(function (spot) {\n            var marker = new google.maps.Marker({\n                position: { lat: spot.lat, lng: spot.lng },\n                map: map,\n                title: spot.title,\n                icon: pinIcon,\n                animation: google.maps.Animation.DROP\n            });\n\n            \/\/ \u2500\u2500 FIX: Build infowindow content using DOM methods so no value\n            \/\/         can ever break out of its context, regardless of content. \u2500\u2500\n            var infowindow = new google.maps.InfoWindow({\n                content: zjmBuildInfoWindow(spot),\n                maxWidth: 300\n            });\n\n            marker.addListener('click', function () {\n                if (openWindow) openWindow.close();\n                infowindow.open(map, marker);\n                openWindow = infowindow;\n            });\n        });\n    }\n\n    \/\/ Builds infowindow HTML safely using DOM \u2014 title is set via textContent\n    \/\/ (never innerHTML) so it cannot inject HTML\/JS regardless of content.\n    \/\/ desc and media_html are already server-sanitized but still scoped safely.\n    function zjmBuildInfoWindow(spot) {\n        var outer = document.createElement('div');\n        outer.style.cssText = 'max-width:280px;font-family:sans-serif;padding:0;';\n\n        \/\/ Title \u2014 textContent ensures NO HTML interpretation\n        var titleEl = document.createElement('div');\n        titleEl.style.cssText = 'margin:0 0 10px;font-size:15px;font-weight:700;color:#333;border-bottom:2px solid #e5f3ff;padding-bottom:6px;line-height:1.3;';\n        titleEl.textContent = spot.title;\n        outer.appendChild(titleEl);\n\n        \/\/ Description \u2014 server-side wp_kses() filtered, safe to use innerHTML\n        if (spot.desc) {\n            var descEl = document.createElement('div');\n            descEl.style.cssText = 'font-size:13px;line-height:1.6;color:#333;margin-bottom:10px;';\n            descEl.innerHTML = spot.desc;\n            outer.appendChild(descEl);\n        }\n\n        \/\/ Media \u2014 server-side esc_url() on all URLs, safe to use innerHTML\n        if (spot.media_html) {\n            var mediaEl = document.createElement('div');\n            mediaEl.innerHTML = spot.media_html;\n            outer.appendChild(mediaEl);\n        }\n\n        return outer;\n    }\n    <\/script>\n    \n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n","protected":false},"excerpt":{"rendered":"","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"footnotes":""},"class_list":["post-110","page","type-page","status-publish"],"_links":{"self":[{"href":"https:\/\/zh2o.ch\/index.php?rest_route=\/wp\/v2\/pages\/110","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/zh2o.ch\/index.php?rest_route=\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/zh2o.ch\/index.php?rest_route=\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/zh2o.ch\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/zh2o.ch\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=110"}],"version-history":[{"count":2,"href":"https:\/\/zh2o.ch\/index.php?rest_route=\/wp\/v2\/pages\/110\/revisions"}],"predecessor-version":[{"id":333,"href":"https:\/\/zh2o.ch\/index.php?rest_route=\/wp\/v2\/pages\/110\/revisions\/333"}],"wp:attachment":[{"href":"https:\/\/zh2o.ch\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=110"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}