WME WazeMY

WME script for WazeMY editing moderation

当前为 2023-07-16 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name WME WazeMY
  3. // @namespace https://greasyfork.org/en/scripts/404584-wazemy
  4. // @version 2023.07.16.01
  5. // @description WME script for WazeMY editing moderation
  6. // @author junyianl
  7. // @match https://beta.waze.com/*
  8. // @match https://www.waze.com/editor*
  9. // @match https://www.waze.com/*/editor*
  10. // @exclude https://www.waze.com/user/editor*
  11. // @require https://greasyfork.org/scripts/24851-wazewrap/code/WazeWrap.js
  12. // @require https://greasyfork.org/scripts/449165-wme-wazemy-trafcamlist/code/wme-wazemy-trafcamlist.js
  13. // @grant GM_xmlhttpRequest
  14. // @license MIT
  15. // ==/UserScript==
  16.  
  17. // @connect p3.fgies.com
  18. // @connect p4.fgies.com
  19. // @connect t2.fgies.com
  20. // @connect jalanow.com
  21. // @connect llm.gov.my
  22.  
  23. /* global W */
  24. /* global WazeWrap */
  25. /* global $ */
  26. /* global OL */
  27. /* global OpenLayers */
  28.  
  29. /**
  30. * All mentions of script names and links in this script is my way of giving
  31. * credit to where it's due.
  32. * Without those scripts, I would have no place to start.
  33. * Big thanks to the original script authors.
  34. *
  35. * Huge thanks to the following contributors for cam locations around Malaysia.
  36. * :: epailxi | dckj | firman_bakti | rickylo103 | kweeheng ::
  37. */
  38.  
  39. // var trafficCamsData = [
  40. // { desc: 'Jalan Sultan Ismail / Jalan Imbi near Berjaya Times Square KL', lat: 3.14369, lon: 101.71245, url: { Jalanow: 'https://p4.fgies.com/kl8/img/K012W.jpg' } },
  41. // { desc: 'PLS CAM C2 SLIM RIVER IC KM372.6 NB', lat: 3.84943, lon: 101.39765, url: {LLM: 'https://www.llm.gov.my/assets/ajax.vigroot.php?h=PLS|PLS CAM C2 SLIM RIVER IC KM372.6 NB'} },
  42. // { desc: 'PLUS-Utara near Tapah KM324.4 SB', lat: 4.236409, lon: 101.255623, url: {Jalanow: 'https://p3.fgies.com/bucket-e1e2/E1E2-22.jpg',LLM: 'https://www.llm.gov.my/assets/ajax.vigroot.php?h=PLS|PLS CAM C1 TAPAH KM324.4 SB'} },
  43. // { desc: 'DUKE CAM 10 SENTUL PASAR KM0.7 NB', lat: 3.19891, lon: 101.69867, url: {Jalanow: 'https://p3.fgies.com/bucket-duke/DUKE-10.jpg',LLM: 'https://www.llm.gov.my/assets/ajax.vigroot.php?h=DUKE'} },
  44. // { desc: 'PLUS-Utara near Slim River KM373.9 NB', lat: 3.841385, lon: 101.407039, url: {Jalanow: 'https://p3.fgies.com/bucket-e1e2/E1E2-06.jpg',LLM: 'https://www.llm.gov.my/assets/ajax.vigroot.php?h=PLS|PLS CAM C2 SLIM RIVER KM373.9 NB'} },
  45. // ];
  46.  
  47. const updateMessage = `
  48. Fixed tooltips after latest WME update.
  49. `;
  50.  
  51. var staticUpdateID;
  52.  
  53. (function () {
  54. 'use strict';
  55.  
  56. var settings = {};
  57.  
  58. console.log("[WazeMY] Bootstrapping...");
  59.  
  60. if (W?.userscripts?.state.isInitialized) {
  61. onInitialized();
  62. } else {
  63. document.addEventListener("wme-initialized", onInitialized, { once:true });
  64. }
  65. function onInitialized() {
  66. if (W?.userscripts?.state.isReady) {
  67. onReady();
  68. } else {
  69. document.addEventListener("wme-ready", onReady, { once:true });
  70. }
  71. }
  72.  
  73. function onReady() {
  74. console.log("[WazeMY] Initializing...");
  75. const { tabLabel, tabPane } = W.userscripts.registerSidebarTab("wazemy");
  76. tabLabel.innerText = "WazeMY";
  77. tabLabel.title = "WazeMY";
  78.  
  79. tabPane.innerHTML = `
  80. <div>
  81. <h4>WazeMY</h4>
  82. <b>${GM_info.script.version}</b>
  83. </div>
  84. <br>
  85. <div id="wazemySettings">
  86. <h6>Settings</h6>
  87. <input type="checkbox" id="wazemySettings_tooltip">
  88. <label for="wazemySettings_tooltip">Map tooltip</label>
  89. <br>
  90. <input type="checkbox" id="wazemySettings_trafcam">
  91. <label for="wazemySettings_trafcam">Traffic cameras</label>
  92. <br>
  93. <br>
  94. </div>
  95. <div>
  96. <h6>Shortcuts</h6>
  97. Ctrl+Alt+C: <i>Copy lat/lon of mouse position to clipboard.</i><br>
  98. </div>
  99. `;
  100.  
  101. wazemyTooltip_init();
  102. wazemyTrafcam_init();
  103. wazemyImgEnlarge_init();
  104.  
  105. WazeWrap.Interface.ShowScriptUpdate(
  106. "WME WazeMY",
  107. GM_info.script.version,
  108. updateMessage,
  109. "https://greasyfork.org/en/scripts/404584-wazemy",
  110. null);
  111. new WazeWrap.Interface.Shortcut(
  112. "WazeMY_latloncopy",
  113. "Copies lat/lon of mouse position",
  114. "wazemy",
  115. "WazeMY",
  116. "CA+c",
  117. wazemyCopyLatLon,
  118. null).add();
  119.  
  120. initializeSettings();
  121.  
  122. console.log("[WazeMY] Initialized.");
  123. }
  124.  
  125. // function onInitialized2() {
  126. // console.log("[WazeMY] Initializing...");
  127. // // Initialize features of WME WazeMY
  128. // wazemyTooltip_init();
  129. // wazemyTrafcam_init();
  130.  
  131. // WazeWrap.Interface.ShowScriptUpdate("WME WazeMY", GM_info.script.version,
  132. // updateMessage, "https://greasyfork.org/en/scripts/404584-wazemy", null);
  133. // // Initialize keyboard shortcuts
  134. // new WazeWrap.Interface.Shortcut('WazeMY_latloncopy',
  135. // 'Copies lat/lon of mouse position', 'wazemy', 'WazeMY', 'CA+c',
  136. // wazemyCopyLatLon, null).add();
  137. // // Initialize Koi later because of dependency on the Settings page.
  138. // // wazemyKoi_init();
  139.  
  140. // console.log("[WazeMY] Init complete.")
  141. // }
  142.  
  143. /* ******* */
  144. /* Tooltip */
  145. /* ******* */
  146. function wazemyTooltip_init() {
  147. let $tooltip = $('<div/>');
  148. $tooltip.attr('id', 'wazemyTooltip');
  149. $tooltip.css({
  150. 'height': 'auto',
  151. 'width': 'auto',
  152. 'background': 'rgba(0,0,0,0.5)',
  153. 'color': 'white',
  154. 'borderRadius': '5px',
  155. 'padding': '5px',
  156. 'position': 'absolute',
  157. 'top': '0px',
  158. 'left': '0px',
  159. 'visibility': 'hidden',
  160. 'zIndex': '10000'
  161. })
  162. $tooltip.appendTo('body');
  163. }
  164.  
  165. function wazemyTooltip_initSettings() {
  166. setChecked('wazemySettings_tooltip', settings.tooltip);
  167. if (settings.tooltip) {
  168. WazeWrap.Events.register('mousemove', null, wazemyTooltip_show);
  169. }
  170. $('#wazemySettings_tooltip').change(function () {
  171. var settingName = $(this)[0].id.substr(15); // strip off the "wazemySettings_" prefix
  172. settings[settingName] = this.checked;
  173. saveSettings();
  174. if (this.checked) {
  175. WazeWrap.Events.register('mousemove', null, wazemyTooltip_show);
  176. }
  177. else {
  178. $('#wazemyTooltip').css('visibility', 'hidden');
  179. WazeWrap.Events.unregister('mousemove', null, wazemyTooltip_show);
  180. }
  181. });
  182. }
  183.  
  184. function wazemyTooltip_show(e) { // from URO+
  185. var result = '';
  186. var showTooltip = false;
  187.  
  188. let landmark = W.map.venueLayer.getFeatureBy('renderIntent', 'highlight');
  189. let segment = W.map.segmentLayer.getFeatureBy('renderIntent', 'highlight');
  190.  
  191. if (landmark != null) {
  192. result = '<b>' + landmark.attributes.wazeFeature._wmeObject.attributes.name + '</b><br>';
  193. let address = landmark.attributes.wazeFeature._wmeObject.getAddress();
  194. try {
  195. result += address.attributes.houseNumber ? (address.attributes.houseNumber + ', ') : ''
  196. result += (address.attributes.street.name ? address.attributes.street.name : 'No street') + '<br>';
  197. result += address.attributes.city.attributes.name + ', ';
  198. result += address.attributes.state.name + '<br>';
  199. }
  200. catch {
  201. result += 'No address<br>';
  202. }
  203. result += '<b>Lock:</b> ' + (landmark.attributes.wazeFeature._wmeObject.getLockRank() + 1);
  204. showTooltip = true;
  205. } else if (segment != null) {
  206. let segmentId = segment.attributes.wazeFeature.id;
  207. // let primaryStreetId = WazeWrap.Model.getPrimaryStreetId(segmentId);
  208. let address = segment.attributes.wazeFeature._wmeObject.getAddress();
  209. result = '<b>';
  210. result += address.attributes.street.name ? address.attributes.street.name : 'No street';
  211. result += '</b><br>';
  212. result += address.attributes.city.attributes.name + ', ' + address.attributes.state.name;
  213. result += '<br>';
  214. result += '<b>ID:</b> ' + segmentId + '<br>';
  215. result += '<b>Lock:</b> ' + (segment.attributes.wazeFeature._wmeObject.getLockRank() + 1);
  216. showTooltip = true;
  217. }
  218.  
  219. if (showTooltip == true) {
  220. let tw = $('#wazemyTooltip').width();
  221. let th = $('#wazemyTooltip').height();
  222. var tooltipX = e.clientX + window.scrollX + 15;
  223. var tooltipY = e.clientY + window.scrollY + 15;
  224. // Handle cases where tooltip is too near the edge.
  225. if ((tooltipX + tw) > W.map.$map.innerWidth()) {
  226. tooltipX -= tw + 20; // 20 = scroll bar size
  227. if (tooltipX < 0) tooltipX = 0;
  228. }
  229. if ((tooltipY + th) > W.map.$map.innerHeight()) {
  230. tooltipY -= th + 20;
  231. if (tooltipY < 0) tooltipY = 0;
  232. }
  233. $('#wazemyTooltip').html(result);
  234. $('#wazemyTooltip').css({
  235. 'top': tooltipY + 'px',
  236. 'left': tooltipX + 'px',
  237. 'visibility': 'visible'
  238. });
  239. } else {
  240. $('#wazemyTooltip').css('visibility', 'hidden');
  241. }
  242. }
  243.  
  244. /* *************** */
  245. /* Traffic cameras */
  246. /* *************** */
  247. // Adapted from WME DOT Cameras
  248. var wazemyTrafcamLayer;
  249.  
  250. function wazemyTrafcam_init() {
  251. if (!OpenLayers.Icon) {
  252. wazemyTrafcam_installIconClass();
  253. }
  254. wazemyTrafcamLayer = new OpenLayers.Layer.Markers("wazemyTrafcamLayer");
  255. W.map.addLayer(wazemyTrafcamLayer);
  256. wazemyTrafcam_showIcons();
  257. wazemyTrafcamLayer.setVisibility(false);
  258. }
  259.  
  260. function wazemyTrafcam_initSettings() {
  261. setChecked('wazemySettings_trafcam', settings.trafcam);
  262. if (settings.trafcam) {
  263. wazemyTrafcamLayer.setVisibility(true);
  264. // WazeWrap.Events.register('moveend', null, wazemyTrafcam_show);
  265. }
  266. $('#wazemySettings_trafcam').change(function () {
  267. var settingName = $(this)[0].id.substr(15); // strip off the "wazemySettings_" prefix
  268. settings[settingName] = this.checked;
  269. saveSettings();
  270. if (this.checked) {
  271. wazemyTrafcamLayer.setVisibility(true);
  272. // WazeWrap.Events.register('moveend', null, wazemyTrafcam_show);
  273. } else {
  274. // WazeWrap.Events.unregister('moveend', null, wazemyTrafcam_show);
  275. wazemyTrafcamLayer.setVisibility(false);
  276. }
  277. });
  278. }
  279.  
  280. function wazemyTrafcam_showIcons() {
  281. trafficCamsData.forEach((e, idx) => {
  282. wazemyTrafcam_drawCamIcon({
  283. idx: idx,
  284. desc: e.desc,
  285. src: e.url,
  286. width: 20,
  287. height: 20,
  288. lat: e.lat,
  289. lon: e.lon
  290. });
  291. });
  292. }
  293.  
  294. function wazemyTrafcam_drawCamIcon(spec) {
  295. const camIcon = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAAGXcA1uAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA2ZpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYxIDY0LjE0MDk0OSwgMjAxMC8xMi8wNy0xMDo1NzowMSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDpBRDNGNTkwRTYzQThFMzExQTc4MDhDNjAwODdEMzdEQSIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDo2OUI0RUEyN0IwRjcxMUUzOERFM0E1OTJCRUY3NTFBOCIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDo2OUI0RUEyNkIwRjcxMUUzOERFM0E1OTJCRUY3NTFBOCIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1LjEgV2luZG93cyI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOjZGOEJBMzExNkZCMEUzMTFCOEY5QTU3QUQxM0M2MjI5IiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOkFEM0Y1OTBFNjNBOEUzMTFBNzgwOEM2MDA4N0QzN0RBIi8+IDwvcmRmOkRlc2NyaXB0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';
  296. let size = new OpenLayers.Size(20, 20);
  297. let icon = new OpenLayers.Icon(camIcon, size);
  298. let epsg4326 = new OpenLayers.Projection("EPSG:4326"); // WGS 1984 projection. Malaysia uses EPSG:900913
  299. let projectTo = W.map.getProjectionObject();
  300. let lonLat = new OpenLayers.LonLat(spec.lon, spec.lat).transform(epsg4326, projectTo);
  301. var newMarker = new OpenLayers.Marker(lonLat, icon);
  302. newMarker.idx = spec.idx;
  303. newMarker.title = spec.desc;
  304. newMarker.url = spec.src;
  305. newMarker.width = spec.width;
  306. newMarker.height = spec.height;
  307. newMarker.location = lonLat;
  308. newMarker.events.register('click', newMarker, wazemyTrafcam_popupCam);
  309. wazemyTrafcamLayer.addMarker(newMarker);
  310. }
  311.  
  312. function wazemyTrafcam_popupCam(e) {
  313. // console.log("wazemyTrafcam_popupCam");
  314.  
  315. clearInterval(staticUpdateID);
  316. $("#gmPopupContainerCam").remove();
  317. $("#gmPopupContainerCam").hide();
  318.  
  319. var popupHTML = ([`
  320. <div id="gmPopupContainerCam" style="margin: 1;text-align: center;padding: 5px;z-index: 1100; position: absolute; color: white; background: rgba(0,0,0,0.5)">
  321. <table border=0>
  322. <tr>
  323. <td><div id="mycamdivheader" style="min-height: 20px;white-space: pre-wrap;white-space: -moz-pre-wrap; white-space: -pre-wrap;white-space: -o-pre-wrap;word-wrap: break-word;width:380px">${this.title}</div></td>
  324. <td align="right"><a href="#close" id="gmCloseCamDlgBtn" title="Close" style="color:red">X</a></td>
  325. </tr>
  326. <tr><td colspan=2>Select source:
  327. <select id="wazemy_camSource">
  328. </select>
  329. <div hidden id="mycamid">${this.idx}</div>
  330. </td></tr>
  331. <tr><td colspan=2><img style="width:400px" id="staticimage"></td></tr>
  332. <tr><td colspan=2><div id="mycamstatus"></div></td></tr>
  333. </table></div>
  334. `]);
  335. $("body").append(popupHTML);
  336.  
  337. for (var urlsrc in this.url) {
  338. if (urlsrc == 'LLM') {
  339. let sp = this.url['LLM'].split('|');
  340. if (sp.length == 2) {
  341. $('#wazemy_camSource').append($('<option>').val(urlsrc).text(urlsrc));
  342. }
  343. } else {
  344. $('#wazemy_camSource').append($('<option>').val(urlsrc).text(urlsrc));
  345. }
  346. }
  347.  
  348. $("#wazemy_camSource").change(function (e) {
  349. switch (this.value) {
  350. case 'Jalanow':
  351. wazemyTrafcam_getJalanowImage(trafficCamsData[$('#mycamid').text()]['url']['Jalanow']);
  352. break;
  353. case 'LLM':
  354. wazemyTrafcam_getLLMImage(trafficCamsData[$('#mycamid').text()]['url']['LLM']);
  355. break;
  356. }
  357. });
  358.  
  359. // Get image for the first time when popup is displayed.
  360. switch (Object.keys(this.url)[0]) {
  361. case 'Jalanow':
  362. wazemyTrafcam_getJalanowImage(this.url['Jalanow']);
  363. break;
  364. case 'LLM':
  365. wazemyTrafcam_getLLMImage(this.url['LLM']);
  366. break;
  367. }
  368.  
  369. // Handle cases where popup is too near the edge.
  370. let tw = $('#gmPopupContainerCam').width();
  371. let th = $('#gmPopupContainerCam').height() + 200;
  372. var tooltipX = e.clientX + window.scrollX + 15;
  373. var tooltipY = e.clientY + window.scrollY + 15;
  374. if ((tooltipX + tw) > W.map.$map.innerWidth()) {
  375. tooltipX -= tw + 20; // 20 = scroll bar size
  376. if (tooltipX < 0) tooltipX = 0;
  377. }
  378. if ((tooltipY + th) > W.map.$map.innerHeight()) {
  379. tooltipY -= th + 20;
  380. if (tooltipY < 0) tooltipY = 0;
  381. }
  382.  
  383. $("#gmPopupContainerCam").css({ left: tooltipX });
  384. $("#gmPopupContainerCam").css({ top: tooltipY });
  385.  
  386. //Add listener for popup's "Close" button
  387. $("#gmCloseCamDlgBtn").click(function () {
  388. clearInterval(staticUpdateID);
  389. $("#gmPopupContainerCam").remove();
  390. $("#gmPopupContainerCam").hide();
  391. });
  392. wazemyTrafcam_dragElement(document.getElementById("gmPopupContainerCam"));
  393.  
  394. }
  395.  
  396. function wazemyTrafcam_getJalanowImage(url) {
  397. GM_xmlhttpRequest({
  398. method: 'GET',
  399. responseType: 'blob',
  400. headers: {
  401. "authority": "p4.fgies.com",
  402. "referer": 'https://www.jalanow.com/',
  403. 'accept': 'image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8'
  404. },
  405. url: url,
  406. onload: function (response) {
  407. document.getElementById('staticimage').src = URL.createObjectURL(response.response);
  408. document.getElementById('mycamstatus').innerHTML = "";
  409. },
  410. onerror: function (response) {
  411. document.getElementById('mycamstatus').innerHTML = "Error loading image.";
  412. },
  413. onprogress: function (response) {
  414. document.getElementById('mycamstatus').innerHTML = "Loading image...";
  415. }
  416. });
  417. }
  418.  
  419. function wazemyTrafcam_getLLMImage(url) {
  420. let camImg = url.split("|");
  421.  
  422. GM_xmlhttpRequest({
  423. method: 'GET',
  424. responseType: 'document',
  425. url: camImg[0],
  426. onload: function (response) {
  427. const re = new RegExp('src="data:image\/png;base64, ([A-Za-z0-9/+=]*)" title="' + camImg[1] + '"');
  428. const m = response.responseText.match(re);
  429. document.getElementById('staticimage').src = "data:image/png;base64," + m[1];
  430. document.getElementById('mycamstatus').innerHTML = "";
  431. },
  432. onerror: function (response) {
  433. document.getElementById('mycamstatus').innerHTML = "Error loading image.";
  434. },
  435. onprogress: function (response) {
  436. document.getElementById('mycamstatus').innerHTML = "Loading image...";
  437. }
  438. })
  439. }
  440.  
  441. function wazemyTrafcam_installIconClass() {
  442. OpenLayers.Icon = OpenLayers.Class({
  443. url: null,
  444. size: null,
  445. offset: null,
  446. calculateOffset: null,
  447. imageDiv: null,
  448. px: null,
  449. initialize: function (a, b, c, d) {
  450. this.url = a;
  451. this.size = b || {
  452. w: 20,
  453. h: 20
  454. };
  455. this.offset = c || {
  456. x: -(this.size.w / 2),
  457. y: -(this.size.h / 2)
  458. };
  459. this.calculateOffset = d;
  460. a = OpenLayers.Util.createUniqueID("OL_Icon_");
  461. let div = this.imageDiv = OpenLayers.Util.createAlphaImageDiv(a);
  462. $(div.firstChild).removeClass('olAlphaImg'); // LEAVE THIS LINE TO PREVENT WME-HARDHATS SCRIPT FROM TURNING ALL ICONS INTO HARDHAT WAZERS --MAPOMATIC
  463. },
  464. destroy: function () {
  465. this.erase();
  466. OpenLayers.Event.stopObservingElement(this.imageDiv.firstChild);
  467. this.imageDiv.innerHTML = "";
  468. this.imageDiv = null;
  469. },
  470. clone: function () {
  471. return new OpenLayers.Icon(this.url, this.size, this.offset, this.calculateOffset);
  472. },
  473. setSize: function (a) {
  474. null !== a && (this.size = a);
  475. this.draw();
  476. },
  477. setUrl: function (a) {
  478. null !== a && (this.url = a);
  479. this.draw();
  480. },
  481. draw: function (a) {
  482. OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv, null, null, this.size, this.url, "absolute");
  483. this.moveTo(a);
  484. return this.imageDiv;
  485. },
  486. erase: function () {
  487. null !== this.imageDiv && null !== this.imageDiv.parentNode && OpenLayers.Element.remove(this.imageDiv);
  488. },
  489. setOpacity: function (a) {
  490. OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv, null, null, null, null, null, null, null, a);
  491. },
  492. moveTo: function (a) {
  493. null !== a && (this.px = a);
  494. null !== this.imageDiv && (null === this.px ? this.display(!1) : (
  495. this.calculateOffset && (this.offset = this.calculateOffset(this.size)),
  496. OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv, null, {
  497. x: this.px.x + this.offset.x,
  498. y: this.px.y + this.offset.y
  499. })
  500. ));
  501. },
  502. display: function (a) {
  503. this.imageDiv.style.display = a ? "" : "none";
  504. },
  505. isDrawn: function () {
  506. return this.imageDiv && this.imageDiv.parentNode && 11 != this.imageDiv.parentNode.nodeType;
  507. },
  508. CLASS_NAME: "OpenLayers.Icon"
  509. });
  510. }
  511.  
  512. // Make the DIV element draggable:
  513. function wazemyTrafcam_dragElement(elmnt) {
  514. var pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;
  515. if (document.getElementById("mycamdivheader")) {
  516. // if present, the header is where you move the DIV from:
  517. document.getElementById("mycamdivheader").onmousedown = dragMouseDown;
  518. } else {
  519. // otherwise, move the DIV from anywhere inside the DIV:
  520. elmnt.onmousedown = dragMouseDown;
  521. }
  522.  
  523. function dragMouseDown(e) {
  524. e = e || window.event;
  525. e.preventDefault();
  526. // get the mouse cursor position at startup:
  527. pos3 = e.clientX;
  528. pos4 = e.clientY;
  529. document.onmouseup = closeDragElement;
  530. // call a function whenever the cursor moves:
  531. document.onmousemove = elementDrag;
  532. }
  533.  
  534. function elementDrag(e) {
  535. e = e || window.event;
  536. e.preventDefault();
  537. // calculate the new cursor position:
  538. pos1 = pos3 - e.clientX;
  539. pos2 = pos4 - e.clientY;
  540. pos3 = e.clientX;
  541. pos4 = e.clientY;
  542. // set the element's new position:
  543. elmnt.style.top = (elmnt.offsetTop - pos2) + "px";
  544. elmnt.style.left = (elmnt.offsetLeft - pos1) + "px";
  545. }
  546.  
  547. function closeDragElement() {
  548. // stop moving when mouse button is released:
  549. document.onmouseup = null;
  550. document.onmousemove = null;
  551. }
  552. }
  553.  
  554. /* ************ */
  555. /* Copy lat/lon */
  556. /* ************ */
  557. function wazemyCopyLatLon() {
  558. copyToClipboard($('.wz-map-ol-control-span-mouse-position').text());
  559. }
  560.  
  561. /* ********************* */
  562. /* PP/PA photos enlarger */
  563. /* ********************* */
  564. function wazemyImgEnlarge_init() {
  565. document.body.addEventListener("click", (e) => {
  566. let venueimg = document.getElementsByClassName("modal-dialog venue-image-dialog");
  567. if (venueimg.length > 0) {
  568. let modaldialog = venueimg[0];
  569. let imglink = modaldialog.getElementsByTagName("img")[0].getAttribute("src");
  570. let newimglink = imglink.replace("thumbs/thumb700_", "");
  571. let venuename = modaldialog.getElementsByClassName("venue-name")[0];
  572. let linktext = modaldialog.getElementsByTagName("a");
  573. if (linktext.length > 0) { // delete old one if exists
  574. linktext[0].remove();
  575. }
  576. venuename.insertAdjacentHTML("afterend", `<a href='${newimglink}' target="_blank" rel="noopener noreferrer">Enlarge</a>`);
  577. }
  578. })
  579. }
  580.  
  581. function initializeSettings() {
  582. loadSettings();
  583.  
  584. wazemyTooltip_initSettings();
  585. wazemyTrafcam_initSettings();
  586. }
  587.  
  588. function saveSettings() {
  589. if (localStorage) {
  590. var localsettings = {
  591. tooltip: settings.tooltip,
  592. trafcam: settings.trafcam
  593. };
  594.  
  595. localStorage.setItem('WME_wazemySettings', JSON.stringify(localsettings));
  596. }
  597. }
  598.  
  599. function loadSettings() {
  600. var loadedSettings = $.parseJSON(localStorage.getItem("WME_wazemySettings"));
  601. var defaultSettings = {
  602. tooltip: false,
  603. };
  604. settings = loadedSettings ? loadedSettings : defaultSettings;
  605. for (var prop in defaultSettings) {
  606. if (!settings.hasOwnProperty(prop)) {
  607. settings[prop] = defaultSettings[prop];
  608. }
  609. }
  610. }
  611.  
  612. function setChecked(checkboxId, checked) {
  613. $('#' + checkboxId).prop('checked', checked);
  614. }
  615.  
  616. // utility functions
  617. var copyToClipboard = function (str) { // from PIE
  618. var $temp = $('<input>');
  619. $('body').append($temp);
  620. $temp.val(str).select();
  621. document.execCommand('copy');
  622. $temp.remove();
  623. };
  624.  
  625. })();