WME WazeMY

WME script for WazeMY editing moderation

当前为 2023-03-21 提交的版本,查看 最新版本

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