WazeWrapBeta

A base library for WME script writers

当前为 2018-04-10 提交的版本,查看 最新版本

此脚本不应直接安装。它是供其他脚本使用的外部库,要使用该库请加入元指令 // @require https://update.gf.qytechs.cn/scripts/24870/264405/WazeWrapBeta.js

  1. // ==UserScript==
  2. // @name WazeWrapBeta
  3. // @namespace https://gf.qytechs.cn/users/30701-justins83-waze
  4. // @version 2018.04.10.03
  5. // @description A base library for WME script writers
  6. // @author JustinS83/MapOMatic
  7. // @include https://beta.waze.com/*editor*
  8. // @include https://www.waze.com/*editor*
  9. // @exclude https://www.waze.com/*user/editor/*
  10. // @grant none
  11. // ==/UserScript==
  12.  
  13. /* global W */
  14. /* global WazeWrap */
  15.  
  16. var WazeWrap = {Ready: false, Version: "2018.04.10.03"};
  17.  
  18. (function() {
  19. 'use strict';
  20. function bootstrap(tries) {
  21. tries = tries || 1;
  22. if(!location.href.match(/^https:\/\/(www|beta)\.waze\.com\/(?!user\/)(.{2,6}\/)?editor\/?.*$/))
  23. return;
  24. if (W && W.map &&
  25. W.model && W.loginManager.user &&
  26. $) {
  27. init();
  28. } else if (tries < 1000) {
  29. setTimeout(function () { bootstrap(tries++); }, 200);
  30. } else {
  31. console.log('WazeWrap failed to load');
  32. }
  33. }
  34.  
  35. bootstrap();
  36.  
  37. function init(){
  38. console.log("WazeWrap initializing...");
  39.  
  40. WazeWrap.isBetaEditor = /beta/.test(location.href);
  41.  
  42. //SetUpRequire();
  43. RestoreMissingSegmentFunctions();
  44.  
  45. WazeWrap.Geometry = new Geometry();
  46. WazeWrap.Model = new Model();
  47. WazeWrap.Interface = new Interface();
  48. WazeWrap.User = new User();
  49. WazeWrap.Util = new Util();
  50. WazeWrap.Require = new Require();
  51. WazeWrap.String = new String();
  52. WazeWrap.getSelectedFeatures = function(){
  53. if(!W.selectionManager.getSelectedFeatures)
  54. return W.selectionManager.selectedItems();
  55. return W.selectionManager.getSelectedFeatures();
  56. }
  57. WazeWrap.hasSelectedFeatures = function(){
  58. if(!W.selectionManager.hasSelectedFeatures)
  59. return W.selectionManager.hasSelectedItems();
  60. return W.selectionManager.hasSelectedFeatures();
  61. }
  62.  
  63. WazeWrap.Ready = true;
  64. window.WazeWrap = WazeWrap;
  65.  
  66. console.log('WazeWrap Loaded');
  67. }
  68.  
  69. function RestoreMissingSegmentFunctions(){
  70. if(W.model.segments.getObjectArray().length > 0){
  71. W.map.events.unregister("moveend", this, RestoreMissingSegmentFunctions);
  72. W.map.events.unregister("zoomend", this, RestoreMissingSegmentFunctions);
  73. if(typeof W.model.segments.getObjectArray()[0].model.getDirection == "undefined")
  74. W.model.segments.getObjectArray()[0].__proto__.getDirection = function(){return (this.attributes.fwdDirection ? 1 : 0) + (this.attributes.revDirection ? 2 : 0);};
  75. if(typeof W.model.segments.getObjectArray()[0].model.isTollRoad == "undefined")
  76. W.model.segments.getObjectArray()[0].__proto__.isTollRoad = function(){ return (this.attributes.fwdToll || this.attributes.revToll);};
  77. }
  78. else{
  79. W.map.events.register("moveend", this, RestoreMissingSegmentFunctions);
  80. W.map.events.register("zoomend", this, RestoreMissingSegmentFunctions);
  81. }
  82. }
  83.  
  84. function Geometry(){
  85. //var geometry = WazeWrap.Geometry;
  86.  
  87. //Converts to "normal" GPS coordinates
  88. this.ConvertTo4326 = function (long, lat){
  89. var projI=new OL.Projection("EPSG:900913");
  90. var projE=new OL.Projection("EPSG:4326");
  91. return (new OL.LonLat(long, lat)).transform(projI,projE);
  92. };
  93.  
  94. this.ConvertTo900913 = function (long, lat){
  95. var projI=new OL.Projection("EPSG:900913");
  96. var projE=new OL.Projection("EPSG:4326");
  97. return (new OL.LonLat(long, lat)).transform(projE,projI);
  98. };
  99.  
  100. //Converts the Longitudinal offset to an offset in 4326 gps coordinates
  101. this.CalculateLongOffsetGPS = function(longMetersOffset, long, lat)
  102. {
  103. var R= 6378137; //Earth's radius
  104. var dLon = longMetersOffset / (R * Math.cos(Math.PI * lat / 180)); //offset in radians
  105. var lon0 = dLon * (180 / Math.PI); //offset degrees
  106.  
  107. return lon0;
  108. };
  109.  
  110. //Converts the Latitudinal offset to an offset in 4326 gps coordinates
  111. this.CalculateLatOffsetGPS = function(latMetersOffset, lat)
  112. {
  113. var R= 6378137; //Earth's radius
  114. var dLat = latMetersOffset/R;
  115. var lat0 = dLat * (180 /Math.PI); //offset degrees
  116.  
  117. return lat0;
  118. };
  119.  
  120. /**
  121. * Checks if the given geometry is on screen
  122. * @function WazeWrap.Geometry.isGeometryInMapExtent
  123. * @param {OL.Geometry} Geometry to check if any part of is in the current viewport
  124. */
  125. this.isLonLatInMapExtent = function (lonLat) {
  126. return lonLat && W.map.getExtent().containsLonLat(lonLat);
  127. };
  128.  
  129. /**
  130. * Checks if the given geometry is on screen
  131. * @function WazeWrap.Geometry.isGeometryInMapExtent
  132. * @param {OL.Geometry} Geometry to check if any part of is in the current viewport
  133. */
  134. this.isGeometryInMapExtent = function (geometry) {
  135. return geometry && geometry.getBounds &&
  136. W.map.getExtent().intersectsBounds(geometry.getBounds());
  137. };
  138.  
  139. /**
  140. * Calculates the distance between two given points, returned in meters
  141. * @function WazeWrap.Geometry.calculateDistance
  142. * @param {OL.Geometry.Point} An array of OL.Geometry.Point with which to measure the total distance. A minimum of 2 points is needed.
  143. */
  144. this.calculateDistance = function(pointArray) {
  145. if(pointArray.length < 2)
  146. return 0;
  147.  
  148. var line = new OL.Geometry.LineString(pointArray);
  149. var length = line.getGeodesicLength(W.map.getProjectionObject());
  150. return length; //multiply by 3.28084 to convert to feet
  151. };
  152.  
  153. this.findClosestSegment = function(mygeometry, ignorePLR, ignoreUnnamedPR){
  154. var onscreenSegments = WazeWrap.Model.getOnscreenSegments();
  155. var minDistance = Infinity;
  156. var closestSegment;
  157.  
  158. for (var s in onscreenSegments) {
  159. if (!onscreenSegments.hasOwnProperty(s))
  160. continue;
  161.  
  162. let segmentType = onscreenSegments[s].attributes.roadType;
  163. if (segmentType === 10 || segmentType === 16 || segmentType === 18 || segmentType === 19) //10 ped boardwalk, 16 stairway, 18 railroad, 19 runway, 3 freeway
  164. continue;
  165.  
  166. if(ignorePLR && segmentType === 20) //PLR
  167. continue;
  168.  
  169. if(ignoreUnnamedPR)
  170. if(segmentType === 17 && WazeWrap.Model.getStreetName(onscreenSegments[s].attributes.primaryStreetID) === null) //PR
  171. continue;
  172.  
  173.  
  174. let distanceToSegment = mygeometry.distanceTo(onscreenSegments[s].geometry, {details: true});
  175.  
  176. if (distanceToSegment.distance < minDistance) {
  177. minDistance = distanceToSegment.distance;
  178. closestSegment = onscreenSegments[s];
  179. closestSegment.closestPoint = new OL.Geometry.Point(distanceToSegment.x1, distanceToSegment.y1);
  180. }
  181. }
  182. return closestSegment;
  183. };
  184. }
  185.  
  186. function Model(){
  187.  
  188. this.getPrimaryStreetID = function(segmentID){
  189. return W.model.segments.get(segmentID).attributes.primaryStreetID;
  190. };
  191.  
  192. this.getStreetName = function(primaryStreetID){
  193. return W.model.streets.get(primaryStreetID).name;
  194. };
  195.  
  196. this.getCityID = function(primaryStreetID){
  197. return W.model.streets.get(primaryStreetID).cityID;
  198. };
  199.  
  200. this.getCityName = function(primaryStreetID){
  201. return W.model.cities.get(this.getCityID(primaryStreetID)).attributes.Name;
  202. };
  203.  
  204. this.getStateName = function(primaryStreetID){
  205. return W.model.states.get(getStateID(primaryStreetID)).Name;
  206. };
  207.  
  208. this.getStateID = function(primaryStreetID){
  209. return W.model.cities.get(primaryStreetID).attributes.stateID;
  210. };
  211.  
  212. this.getCountryID = function(primaryStreetID){
  213. return W.model.cities.get(this.getCityID(primaryStreetID)).attributes.CountryID;
  214. };
  215.  
  216. this.getCountryName = function(primaryStreetID){
  217. return W.model.countries.get(getCountryID(primaryStreetID)).name;
  218. };
  219.  
  220. this.getCityNameFromSegmentObj = function(segObj){
  221. return this.getCityName(segObj.attributes.primaryStreetID);
  222. };
  223.  
  224. this.getStateNameFromSegmentObj = function(segObj){
  225. return this.getStateName(segObj.attributes.primaryStreetID);
  226. };
  227.  
  228. //returns an array of segmentIDs for all segments that are part of the same roundabout as the passed segment
  229. this.getAllRoundaboutSegmentsFromObj = function(segObj){
  230. if(segObj.model.attributes.junctionID === null)
  231. return null;
  232.  
  233. return W.model.junctions.objects[segObj.model.attributes.junctionID].attributes.segIDs;
  234. };
  235.  
  236. this.getAllRoundaboutJunctionNodesFromObj = function(segObj){
  237. var RASegs = this.getAllRoundaboutSegmentsFromObj(segObj);
  238. var RAJunctionNodes = [];
  239. for(i=0; i< RASegs.length; i++){
  240. RAJunctionNodes.push(W.model.nodes.objects[W.model.segments.get(RASegs[i]).attributes.toNodeID]);
  241.  
  242. }
  243. return RAJunctionNodes;
  244. };
  245.  
  246. this.isRoundaboutSegmentID = function(segmentID){
  247. if(W.model.segments.get(segmentID).attributes.junctionID === null)
  248. return false;
  249. else
  250. return true;
  251. };
  252.  
  253. this.isRoundaboutSegmentObj = function(segObj){
  254. if(segObj.model.attributes.junctionID === null)
  255. return false;
  256. else
  257. return true;
  258. };
  259.  
  260. this.getOnscreenSegments = function(){
  261. var segments = W.model.segments.objects;
  262. var mapExtent = W.map.getExtent();
  263. var onScreenSegments = [];
  264. var seg;
  265.  
  266. for (var s in segments) {
  267. if (!segments.hasOwnProperty(s))
  268. continue;
  269.  
  270. seg = W.model.segments.get(s);
  271. if (mapExtent.intersectsBounds(seg.geometry.getBounds()))
  272. onScreenSegments.push(seg);
  273. }
  274. return onScreenSegments;
  275. };
  276.  
  277. /**
  278. * Defers execution of a callback function until the WME map and data
  279. * model are ready. Call this function before calling a function that
  280. * causes a map and model reload, such as W.map.moveTo(). After the
  281. * move is completed the callback function will be executed.
  282. * @function WazeWrap.Model.onModelReady
  283. * @param {Function} callback The callback function to be executed.
  284. * @param {Boolean} now Whether or not to call the callback now if the
  285. * model is currently ready.
  286. * @param {Object} context The context in which to call the callback.
  287. */
  288. this.onModelReady = function (callback, now, context) {
  289. var deferModelReady = function () {
  290. return $.Deferred(function (dfd) {
  291. var resolve = function () {
  292. dfd.resolve();
  293. W.model.events.unregister('mergeend', null, resolve);
  294. };
  295. W.model.events.register('mergeend', null, resolve);
  296. }).promise();
  297. };
  298. var deferMapReady = function () {
  299. return $.Deferred(function (dfd) {
  300. var resolve = function () {
  301. dfd.resolve();
  302. W.vent.off('operationDone', resolve);
  303. };
  304. W.vent.on('operationDone', resolve);
  305. }).promise();
  306. };
  307.  
  308. if (typeof callback === 'function') {
  309. context = context || callback;
  310. if (now && WazeWrap.Util.mapReady() && WazeWrap.Util.modelReady()) {
  311. callback.call(context);
  312. } else {
  313. $.when(deferMapReady() && deferModelReady()).
  314. then(function () {
  315. callback.call(context);
  316. });
  317. }
  318. }
  319. };
  320.  
  321. /**
  322. * Retrives a route from the Waze Live Map.
  323. * @class
  324. * @name wLib.Model.RouteSelection
  325. * @param firstSegment The segment to use as the start of the route.
  326. * @param lastSegment The segment to use as the destination for the route.
  327. * @param {Array|Function} callback A function or array of funcitons to be
  328. * executed after the route
  329. * is retrieved. 'This' in the callback functions will refer to the
  330. * RouteSelection object.
  331. * @param {Object} options A hash of options for determining route. Valid
  332. * options are:
  333. * fastest: {Boolean} Whether or not the fastest route should be used.
  334. * Default is false, which selects the shortest route.
  335. * freeways: {Boolean} Whether or not to avoid freeways. Default is false.
  336. * dirt: {Boolean} Whether or not to avoid dirt roads. Default is false.
  337. * longtrails: {Boolean} Whether or not to avoid long dirt roads. Default
  338. * is false.
  339. * uturns: {Boolean} Whether or not to allow U-turns. Default is true.
  340. * @return {wLib.Model.RouteSelection} The new RouteSelection object.
  341. * @example: // The following example will retrieve a route from the Live Map and select the segments in the route.
  342. * selection = W.selectionManager.selectedItems;
  343. * myRoute = new wLib.Model.RouteSelection(selection[0], selection[1], function(){this.selectRouteSegments();}, {fastest: true});
  344. */
  345. this.RouteSelection = function (firstSegment, lastSegment, callback, options) {
  346. var i,
  347. n,
  348. start = this.getSegmentCenterLonLat(firstSegment),
  349. end = this.getSegmentCenterLonLat(lastSegment);
  350. this.options = {
  351. fastest: options && options.fastest || false,
  352. freeways: options && options.freeways || false,
  353. dirt: options && options.dirt || false,
  354. longtrails: options && options.longtrails || false,
  355. uturns: options && options.uturns || true
  356. };
  357. this.requestData = {
  358. from: 'x:' + start.x + ' y:' + start.y + ' bd:true',
  359. to: 'x:' + end.x + ' y:' + end.y + ' bd:true',
  360. returnJSON: true,
  361. returnGeometries: true,
  362. returnInstructions: false,
  363. type: this.options.fastest ? 'HISTORIC_TIME' : 'DISTANCE',
  364. clientVersion: '4.0.0',
  365. timeout: 60000,
  366. nPaths: 3,
  367. options: this.setRequestOptions(this.options)
  368. };
  369. this.callbacks = [];
  370. if (callback) {
  371. if (!(callback instanceof Array)) {
  372. callback = [callback];
  373. }
  374. for (i = 0, n = callback.length; i < n; i++) {
  375. if ('function' === typeof callback[i]) {
  376. this.callbacks.push(callback[i]);
  377. }
  378. }
  379. }
  380. this.routeData = null;
  381. this.getRouteData();
  382. };
  383.  
  384. this.RouteSelection.prototype =
  385. /** @lends wLib.Model.RouteSelection.prototype */ {
  386.  
  387. /**
  388. * Formats the routing options string for the ajax request.
  389. * @private
  390. * @param {Object} options Object containing the routing options.
  391. * @return {String} String containing routing options.
  392. */
  393. setRequestOptions: function (options) {
  394. return 'AVOID_TOLL_ROADS:' + (options.tolls ? 't' : 'f') + ',' +
  395. 'AVOID_PRIMARIES:' + (options.freeways ? 't' : 'f') + ',' +
  396. 'AVOID_TRAILS:' + (options.dirt ? 't' : 'f') + ',' +
  397. 'AVOID_LONG_TRAILS:' + (options.longtrails ? 't' : 'f') + ',' +
  398. 'ALLOW_UTURNS:' + (options.uturns ? 't' : 'f');
  399. },
  400.  
  401. /**
  402. * Gets the center of a segment in LonLat form.
  403. * @private
  404. * @param segment A Waze model segment object.
  405. * @return {OL.LonLat} The LonLat object corresponding to the
  406. * center of the segment.
  407. */
  408. getSegmentCenterLonLat: function (segment) {
  409. var x, y, componentsLength, midPoint;
  410. if (segment) {
  411. componentsLength = segment.geometry.components.length;
  412. midPoint = Math.floor(componentsLength / 2);
  413. if (componentsLength % 2 === 1) {
  414. x = segment.geometry.components[midPoint].x;
  415. y = segment.geometry.components[midPoint].y;
  416. } else {
  417. x = (segment.geometry.components[midPoint - 1].x +
  418. segment.geometry.components[midPoint].x) / 2;
  419. y = (segment.geometry.components[midPoint - 1].y +
  420. segment.geometry.components[midPoint].y) / 2;
  421. }
  422. return new OL.Geometry.Point(x, y).
  423. transform(W.map.getProjectionObject(), 'EPSG:4326');
  424. }
  425.  
  426. },
  427.  
  428. /**
  429. * Gets the route from Live Map and executes any callbacks upon success.
  430. * @private
  431. * @returns The ajax request object. The responseJSON property of the
  432. * returned object
  433. * contains the route information.
  434. *
  435. */
  436. getRouteData: function () {
  437. var i,
  438. n,
  439. that = this;
  440. return $.ajax({
  441. dataType: 'json',
  442. url: this.getURL(),
  443. data: this.requestData,
  444. dataFilter: function (data, dataType) {
  445. return data.replace(/NaN/g, '0');
  446. },
  447. success: function (data) {
  448. that.routeData = data;
  449. for (i = 0, n = that.callbacks.length; i < n; i++) {
  450. that.callbacks[i].call(that);
  451. }
  452. }
  453. });
  454. },
  455.  
  456. /**
  457. * Extracts the IDs from all segments on the route.
  458. * @private
  459. * @return {Array} Array containing an array of segment IDs for
  460. * each route alternative.
  461. */
  462. getRouteSegmentIDs: function () {
  463. var i, j, route, len1, len2, segIDs = [],
  464. routeArray = [],
  465. data = this.routeData;
  466. if ('undefined' !== typeof data.alternatives) {
  467. for (i = 0, len1 = data.alternatives.length; i < len1; i++) {
  468. route = data.alternatives[i].response.results;
  469. for (j = 0, len2 = route.length; j < len2; j++) {
  470. routeArray.push(route[j].path.segmentId);
  471. }
  472. segIDs.push(routeArray);
  473. routeArray = [];
  474. }
  475. } else {
  476. route = data.response.results;
  477. for (i = 0, len1 = route.length; i < len1; i++) {
  478. routeArray.push(route[i].path.segmentId);
  479. }
  480. segIDs.push(routeArray);
  481. }
  482. return segIDs;
  483. },
  484.  
  485. /**
  486. * Gets the URL to use for the ajax request based on country.
  487. * @private
  488. * @return {String} Relative URl to use for route ajax request.
  489. */
  490. getURL: function () {
  491. if (W.model.countries.get(235) || W.model.countries.get(40)) {
  492. return '/RoutingManager/routingRequest';
  493. } else if (W.model.countries.get(106)) {
  494. return '/il-RoutingManager/routingRequest';
  495. } else {
  496. return '/row-RoutingManager/routingRequest';
  497. }
  498. },
  499.  
  500. /**
  501. * Selects all segments on the route in the editor.
  502. * @param {Integer} routeIndex The index of the alternate route.
  503. * Default route to use is the first one, which is 0.
  504. */
  505. selectRouteSegments: function (routeIndex) {
  506. var i, n, seg,
  507. segIDs = this.getRouteSegmentIDs()[Math.floor(routeIndex) || 0],
  508. segments = [];
  509. if ('undefined' === typeof segIDs) {
  510. return;
  511. }
  512. for (i = 0, n = segIDs.length; i < n; i++) {
  513. seg = W.model.segments.get(segIDs[i]);
  514. if ('undefined' !== seg) {
  515. segments.push(seg);
  516. }
  517. }
  518. return W.selectionManager.select(segments);
  519. }
  520. };
  521. }
  522.  
  523. function User(){
  524. this.Rank = function(){
  525. return W.loginManager.user.normalizedLevel;
  526. };
  527.  
  528. this.Username = function(){
  529. return W.loginManager.user.userName;
  530. };
  531.  
  532. this.isCM = function(){
  533. if(W.loginManager.user.editableCountryIDs.length > 0)
  534. return true;
  535. else
  536. return false;
  537. };
  538.  
  539. this.isAM = function(){
  540. return W.loginManager.user.isAreaManager;
  541. };
  542. }
  543.  
  544. function Require(){
  545. this.DragElement = function(){
  546. var myDragElement = OL.Class({
  547. started: !1,
  548. stopDown: !0,
  549. dragging: !1,
  550. touch: !1,
  551. last: null ,
  552. start: null ,
  553. lastMoveEvt: null ,
  554. oldOnselectstart: null ,
  555. interval: 0,
  556. timeoutId: null ,
  557. forced: !1,
  558. active: !1,
  559. initialize: function(e) {
  560. this.map = e,
  561. this.uniqueID = myDragElement.baseID--
  562. },
  563. callback: function(e, t) {
  564. if (this[e])
  565. return this[e].apply(this, t)
  566. },
  567. dragstart: function(e) {
  568. e.xy = new OL.Pixel(e.clientX - this.map.viewPortDiv.offsets[0],e.clientY - this.map.viewPortDiv.offsets[1]);
  569. var t = !0;
  570. return this.dragging = !1,
  571. (OL.Event.isLeftClick(e) || OL.Event.isSingleTouch(e)) && (this.started = !0,
  572. this.start = e.xy,
  573. this.last = e.xy,
  574. OL.Element.addClass(this.map.viewPortDiv, "olDragDown"),
  575. this.down(e),
  576. this.callback("down", [e.xy]),
  577. OL.Event.stop(e),
  578. this.oldOnselectstart || (this.oldOnselectstart = document.onselectstart ? document.onselectstart : OL.Function.True),
  579. document.onselectstart = OL.Function.False,
  580. t = !this.stopDown),
  581. t
  582. },
  583. forceStart: function() {
  584. var e = arguments.length > 0 && void 0 !== arguments[0] && arguments[0];
  585. return this.started = !0,
  586. this.endOnMouseUp = e,
  587. this.forced = !0,
  588. this.last = {
  589. x: 0,
  590. y: 0
  591. },
  592. this.callback("force")
  593. },
  594. forceEnd: function() {
  595. if (this.forced)
  596. return this.endDrag()
  597. },
  598. dragmove: function(e) {
  599. return this.map.viewPortDiv.offsets && (e.xy = new OL.Pixel(e.clientX - this.map.viewPortDiv.offsets[0],e.clientY - this.map.viewPortDiv.offsets[1])),
  600. this.lastMoveEvt = e,
  601. !this.started || this.timeoutId || e.xy.x === this.last.x && e.xy.y === this.last.y || (this.interval > 0 && (this.timeoutId = window.setTimeout(OL.Function.bind(this.removeTimeout, this), this.interval)),
  602. this.dragging = !0,
  603. this.move(e),
  604. this.oldOnselectstart || (this.oldOnselectstart = document.onselectstart,
  605. document.onselectstart = OL.Function.False),
  606. this.last = e.xy),
  607. !0
  608. },
  609. dragend: function(e) {
  610. if (e.xy = new OL.Pixel(e.clientX - this.map.viewPortDiv.offsets[0],e.clientY - this.map.viewPortDiv.offsets[1]),
  611. this.started) {
  612. var t = this.start !== this.last;
  613. this.endDrag(),
  614. this.up(e),
  615. this.callback("up", [e.xy]),
  616. t && this.callback("done", [e.xy])
  617. }
  618. return !0
  619. },
  620. endDrag: function() {
  621. this.started = !1,
  622. this.dragging = !1,
  623. this.forced = !1,
  624. OL.Element.removeClass(this.map.viewPortDiv, "olDragDown"),
  625. document.onselectstart = this.oldOnselectstart
  626. },
  627. down: function(e) {},
  628. move: function(e) {},
  629. up: function(e) {},
  630. out: function(e) {},
  631. mousedown: function(e) {
  632. return this.dragstart(e)
  633. },
  634. touchstart: function(e) {
  635. return this.touch || (this.touch = !0,
  636. this.map.events.un({
  637. mousedown: this.mousedown,
  638. mouseup: this.mouseup,
  639. mousemove: this.mousemove,
  640. click: this.click,
  641. scope: this
  642. })),
  643. this.dragstart(e)
  644. },
  645. mousemove: function(e) {
  646. return this.dragmove(e)
  647. },
  648. touchmove: function(e) {
  649. return this.dragmove(e)
  650. },
  651. removeTimeout: function() {
  652. if (this.timeoutId = null ,
  653. this.dragging)
  654. return this.mousemove(this.lastMoveEvt)
  655. },
  656. mouseup: function(e) {
  657. if (!this.forced || this.endOnMouseUp)
  658. return this.started ? this.dragend(e) : void 0
  659. },
  660. touchend: function(e) {
  661. if (e.xy = this.last,
  662. !this.forced)
  663. return this.dragend(e)
  664. },
  665. click: function(e) {
  666. return this.start === this.last
  667. },
  668. activate: function(e) {
  669. this.$el = e,
  670. this.active = !0;
  671. var t = $(this.map.viewPortDiv);
  672. return this.$el.on("mousedown.drag-" + this.uniqueID, $.proxy(this.mousedown, this)),
  673. this.$el.on("touchstart.drag-" + this.uniqueID, $.proxy(this.touchstart, this)),
  674. $(document).on("mouseup.drag-" + this.uniqueID, $.proxy(this.mouseup, this)),
  675. t.on("mousemove.drag-" + this.uniqueID, $.proxy(this.mousemove, this)),
  676. t.on("touchmove.drag-" + this.uniqueID, $.proxy(this.touchmove, this)),
  677. t.on("touchend.drag-" + this.uniqueID, $.proxy(this.touchend, this))
  678. },
  679. deactivate: function() {
  680. return this.active = !1,
  681. this.$el.off(".drag-" + this.uniqueID),
  682. $(this.map.viewPortDiv).off(".drag-" + this.uniqueID),
  683. $(document).off(".drag-" + this.uniqueID),
  684. this.touch = !1,
  685. this.started = !1,
  686. this.forced = !1,
  687. this.dragging = !1,
  688. this.start = null ,
  689. this.last = null ,
  690. OL.Element.removeClass(this.map.viewPortDiv, "olDragDown")
  691. },
  692. adjustXY: function(e) {
  693. var t = OL.Util.pagePosition(this.map.viewPortDiv);
  694. return e.xy.x -= t[0],
  695. e.xy.y -= t[1]
  696. },
  697. CLASS_NAME: "W.Handler.DragElement"
  698. });
  699. myDragElement.baseID = 0;
  700. return myDragElement;
  701. };
  702.  
  703. this.DivIcon = OL.Class({
  704. className: null ,
  705. $div: null ,
  706. events: null ,
  707. initialize: function(e, t) {
  708. this.className = e,
  709. this.moveWithTransform = !!t,
  710. this.$div = $("<div />").addClass(e),
  711. this.div = this.$div.get(0),
  712. this.imageDiv = this.$div.get(0);
  713. },
  714. destroy: function() {
  715. this.erase(),
  716. this.$div = null;
  717. },
  718. clone: function() {
  719. return new i(this.className);
  720. },
  721. draw: function(e) {
  722. return this.moveWithTransform ? (this.$div.css({
  723. transform: "translate(" + e.x + "px, " + e.y + "px)"
  724. }),
  725. this.$div.css({
  726. position: "absolute"
  727. })) : this.$div.css({
  728. position: "absolute",
  729. left: e.x,
  730. top: e.y
  731. }),
  732. this.$div.get(0);
  733. },
  734. moveTo: function(e) {
  735. null !== e && (this.px = e),
  736. null === this.px ? this.display(!1) : this.moveWithTransform ? this.$div.css({
  737. transform: "translate(" + this.px.x + "px, " + this.px.y + "px)"
  738. }) : this.$div.css({
  739. left: this.px.x,
  740. top: this.px.y
  741. });
  742. },
  743. erase: function() {
  744. this.$div.remove();
  745. },
  746. display: function(e) {
  747. this.$div.toggle(e);
  748. },
  749. isDrawn: function() {
  750. return !!this.$div.parent().length;
  751. },
  752. bringToFront: function() {
  753. if (this.isDrawn()) {
  754. var e = this.$div.parent();
  755. this.$div.detach().appendTo(e);
  756. }
  757. },
  758. forceReflow: function() {
  759. return this.$div.get(0).offsetWidth;
  760. },
  761. CLASS_NAME: "W.DivIcon"
  762. });
  763. }
  764.  
  765.  
  766. function Util(){
  767. /**
  768. * Function to defer function execution until an element is present on
  769. * the page.
  770. * @function WazeWrap.Util.waitForElement
  771. * @param {String} selector The CSS selector string or a jQuery object
  772. * to find before executing the callback.
  773. * @param {Function} callback The function to call when the page
  774. * element is detected.
  775. * @param {Object} [context] The context in which to call the callback.
  776. */
  777. this.waitForElement = function (selector, callback, context) {
  778. var jqObj;
  779.  
  780. if (!selector || typeof callback !== 'function') {
  781. return;
  782. }
  783.  
  784. jqObj = typeof selector === 'string' ?
  785. $(selector) : selector instanceof $ ? selector : null;
  786.  
  787. if (!jqObj.size()) {
  788. window.requestAnimationFrame(function () {
  789. WazeWrap.Util.waitForElement(selector, callback, context);
  790. });
  791. } else {
  792. callback.call(context || callback);
  793. }
  794. };
  795.  
  796. /**
  797. * Function to track the ready state of the map.
  798. * @function WazeWrap.Util.mapReady
  799. * @return {Boolean} Whether or not a map operation is pending or
  800. * undefined if the function has not yet seen a map ready event fired.
  801. */
  802. this.mapReady = function () {
  803. var mapReady = true;
  804. W.vent.on('operationPending', function () {
  805. mapReady = false;
  806. });
  807. W.vent.on('operationDone', function () {
  808. mapReady = true;
  809. });
  810. return function () {
  811. return mapReady;
  812. };
  813. } ();
  814.  
  815. /**
  816. * Function to track the ready state of the model.
  817. * @function WazeWrap.Util.modelReady
  818. * @return {Boolean} Whether or not the model has loaded objects or
  819. * undefined if the function has not yet seen a model ready event fired.
  820. */
  821. this.modelReady = function () {
  822. var modelReady = true;
  823. W.model.events.register('mergestart', null, function () {
  824. modelReady = false;
  825. });
  826. W.model.events.register('mergeend', null, function () {
  827. modelReady = true;
  828. });
  829. return function () {
  830. return modelReady;
  831. };
  832. } ();
  833. }
  834.  
  835. function Interface() {
  836. /**
  837. * Generates id for message bars.
  838. * @private
  839. */
  840. var getNextID = function () {
  841. var id = 1;
  842. return function () {
  843. return id++;
  844. };
  845. } ();
  846.  
  847. this.Shortcut = class Shortcut{
  848. constructor(name, desc, group, title, shortcut, callback, scope){
  849. if ('string' === typeof name && name.length > 0 && 'string' === typeof shortcut && 'function' === typeof callback) {
  850. this.name = name;
  851. this.desc = desc;
  852. this.group = group || this.defaults.group;
  853. this.title = title;
  854. this.callback = callback;
  855. this.shortcut = {};
  856. this.shortcut[shortcut] = name;
  857. if ('object' !== typeof scope)
  858. this.scope = null;
  859. else
  860. this.scope = scope;
  861. this.groupExists = false;
  862. this.actionExists = false;
  863. this.eventExists = false;
  864. this.defaults = {group: 'default'};
  865.  
  866. return this;
  867. }
  868. }
  869.  
  870. /**
  871. * Determines if the shortcut's action already exists.
  872. * @private
  873. */
  874. doesGroupExist(){
  875. this.groupExists = 'undefined' !== typeof W.accelerators.Groups[this.group] &&
  876. undefined !== typeof W.accelerators.Groups[this.group].members;
  877. return this.groupExists;
  878. }
  879.  
  880. /**
  881. * Determines if the shortcut's action already exists.
  882. * @private
  883. */
  884. doesActionExist() {
  885. this.actionExists = 'undefined' !== typeof W.accelerators.Actions[this.name];
  886. return this.actionExists;
  887. }
  888.  
  889. /**
  890. * Determines if the shortcut's event already exists.
  891. * @private
  892. */
  893. doesEventExist() {
  894. this.eventExists = 'undefined' !== typeof W.accelerators.events.listeners[this.name] &&
  895. W.accelerators.events.listeners[this.name].length > 0 &&
  896. this.callback === W.accelerators.events.listeners[this.name][0].func &&
  897. this.scope === W.accelerators.events.listeners[this.name][0].obj;
  898. return this.eventExists;
  899. }
  900.  
  901. /**
  902. * Creates the shortcut's group.
  903. * @private
  904. */
  905. createGroup() {
  906. W.accelerators.Groups[this.group] = [];
  907. W.accelerators.Groups[this.group].members = [];
  908.  
  909. if(this.title && !I18n.translations[I18n.currentLocale()].keyboard_shortcuts.groups[this.group]){
  910. I18n.translations[I18n.currentLocale()].keyboard_shortcuts.groups[this.group] = [];
  911. I18n.translations[I18n.currentLocale()].keyboard_shortcuts.groups[this.group].description = this.title;
  912. I18n.translations[I18n.currentLocale()].keyboard_shortcuts.groups[this.group].members = [];
  913. }
  914. }
  915.  
  916. /**
  917. * Registers the shortcut's action.
  918. * @private
  919. */
  920. addAction(){
  921. if(this.title)
  922. I18n.translations[I18n.currentLocale()].keyboard_shortcuts.groups[this.group].members[this.name] = this.desc;
  923. W.accelerators.addAction(this.name, { group: this.group });
  924. }
  925.  
  926. /**
  927. * Registers the shortcut's event.
  928. * @private
  929. */
  930. addEvent(){
  931. W.accelerators.events.register(this.name, this.scope, this.callback);
  932. }
  933.  
  934. /**
  935. * Registers the shortcut's keyboard shortcut.
  936. * @private
  937. */
  938. registerShortcut() {
  939. W.accelerators._registerShortcuts(this.shortcut);
  940. }
  941.  
  942. /**
  943. * Adds the keyboard shortcut to the map.
  944. * @return {WazeWrap.Interface.Shortcut} The keyboard shortcut.
  945. */
  946. add(){
  947. /* If the group is not already defined, initialize the group. */
  948. if (!this.doesGroupExist()) {
  949. this.createGroup();
  950. }
  951.  
  952. /* Clear existing actions with same name */
  953. if (this.doesActionExist()) {
  954. W.accelerators.Actions[this.name] = null;
  955. }
  956. this.addAction();
  957.  
  958. /* Register event only if it's not already registered */
  959. if (!this.doesEventExist()) {
  960. this.addEvent();
  961. }
  962.  
  963. /* Finally, register the shortcut. */
  964. this.registerShortcut();
  965. return this;
  966. }
  967.  
  968. /**
  969. * Removes the keyboard shortcut from the map.
  970. * @return {WazeWrap.Interface.Shortcut} The keyboard shortcut.
  971. */
  972. remove() {
  973. if (this.doesEventExist()) {
  974. W.accelerators.events.unregister(this.name, this.scope, this.callback);
  975. }
  976. if (this.doesActionExist()) {
  977. delete W.accelerators.Actions[this.name];
  978. }
  979. //remove shortcut?
  980. return this;
  981. }
  982.  
  983. /**
  984. * Changes the keyboard shortcut and applies changes to the map.
  985. * @return {WazeWrap.Interface.Shortcut} The keyboard shortcut.
  986. */
  987. change (shortcut) {
  988. if (shortcut) {
  989. this.shortcut = {};
  990. this.shortcut[shortcut] = this.name;
  991. this.registerShortcut();
  992. }
  993. return this;
  994. }
  995. }
  996.  
  997. this.Tab = class Tab{
  998. constructor(name, content, callback, context){
  999. this.TAB_SELECTOR = '#user-tabs ul.nav-tabs';
  1000. this.CONTENT_SELECTOR = '#user-info div.tab-content';
  1001. this.callback = null;
  1002. this.$content = null;
  1003. this.context = null;
  1004. this.$tab = null;
  1005. let idName, i = 0;
  1006. if (name && 'string' === typeof name &&
  1007. content && 'string' === typeof content) {
  1008. if (callback && 'function' === typeof callback) {
  1009. this.callback = callback;
  1010. this.context = context || callback;
  1011. }
  1012. /* Sanitize name for html id attribute */
  1013. idName = name.toLowerCase().replace(/[^a-z-_]/g, '');
  1014. /* Make sure id will be unique on page */
  1015. while (
  1016. $('#sidepanel-' + (i ? idName + i : idName)).length > 0) {
  1017. i++;
  1018. }
  1019. if (i) {
  1020. idName = idName + i;
  1021. }
  1022. /* Create tab and content */
  1023. this.$tab = $('<li/>')
  1024. .append($('<a/>')
  1025. .attr({
  1026. 'href': '#sidepanel-' + idName,
  1027. 'data-toggle': 'tab',
  1028. })
  1029. .text(name));
  1030. this.$content = $('<div/>')
  1031. .addClass('tab-pane')
  1032. .attr('id', 'sidepanel-' + idName)
  1033. .html(content);
  1034.  
  1035. this.appendTab();
  1036. let that = this;
  1037. if (W.prefs) {
  1038. W.prefs.on('change:isImperial', function(){that.appendTab();});
  1039. }
  1040. W.app.modeController.model.bind('change:mode', function(){that.appendTab();});
  1041. }
  1042. }
  1043. append(content){
  1044. this.$content.append(content);
  1045. }
  1046. appendTab(){
  1047. WazeWrap.Util.waitForElement(
  1048. this.TAB_SELECTOR + ',' + this.CONTENT_SELECTOR,
  1049. function () {
  1050. $(this.TAB_SELECTOR).append(this.$tab);
  1051. $(this.CONTENT_SELECTOR).first().append(this.$content);
  1052. if (this.callback) {
  1053. this.callback.call(this.context);
  1054. }
  1055. }, this);
  1056. }
  1057. clearContent(){
  1058. this.$content.empty();
  1059. }
  1060. destroy(){
  1061. this.$tab.remove();
  1062. this.$content.remove();
  1063. }
  1064. }
  1065.  
  1066. this.AddLayerCheckbox = function(group, checkboxText, checked, callback){
  1067. group = group.toLowerCase();
  1068. var normalizedText = checkboxText.toLowerCase().replace(/\s/g, '_');
  1069. var checkboxID = "layer-switcher-item_" + normalizedText;
  1070. var groupPrefix = 'layer-switcher-group_';
  1071. var groupClass = groupPrefix + group.toLowerCase();
  1072. sessionStorage[normalizedText] = checked;
  1073.  
  1074. var CreateParentGroup = function(groupChecked){
  1075. var groupList = $('.layer-switcher').find('.list-unstyled.togglers');
  1076. var checkboxText = group.charAt(0).toUpperCase() + group.substr(1);
  1077. var newLI = $('<li class="group">');
  1078. newLI.html([
  1079. '<div class="controls-container toggler">',
  1080. '<input class="' + groupClass + '" id="' + groupClass + '" type="checkbox" ' + (groupChecked ? 'checked' : '') +'>',
  1081. '<label for="' + groupClass + '">',
  1082. '<span class="label-text">'+ checkboxText + '</span>',
  1083. '</label></div>',
  1084. '<ul class="children"></ul>'
  1085. ].join(' '));
  1086.  
  1087. groupList.append(newLI);
  1088. $('#' + groupClass).change(function(){sessionStorage[groupClass] = this.checked;});
  1089. };
  1090.  
  1091. if(group !== "issues" && group !== "places" && group !== "road" && group !== "display") //"non-standard" group, check its existence
  1092. if($('.'+groupClass).length === 0){ //Group doesn't exist yet, create it
  1093. var isParentChecked = (typeof sessionStorage[groupClass] == "undefined" ? true : sessionStorage[groupClass]=='true');
  1094. CreateParentGroup(isParentChecked); //create the group
  1095. sessionStorage[groupClass] = isParentChecked;
  1096.  
  1097. W.app.modeController.model.bind('change:mode', function(model, modeId, context){ //make it reappear after changing modes
  1098. CreateParentGroup((sessionStorage[groupClass]=='true'));
  1099. });
  1100. }
  1101.  
  1102. var buildLayerItem = function(isChecked){
  1103. var groupChildren = $("."+groupClass).parent().parent().find('.children').not('.extended');
  1104. let $li = $('<li>');
  1105. $li.html([
  1106. '<div class="controls-container toggler">',
  1107. '<input type="checkbox" id="' + checkboxID + '" class="' + checkboxID + ' toggle">',
  1108. '<label for="' + checkboxID + '"><span class="label-text">' + checkboxText + '</span></label>',
  1109. '</div>',
  1110. ].join(' '));
  1111.  
  1112. groupChildren.append($li);
  1113. $('#' + checkboxID).prop('checked', isChecked);
  1114. $('#' + checkboxID).change(function(){callback(this.checked); sessionStorage[normalizedText] = this.checked;});
  1115. if(!$('#' + groupClass).is(':checked')){
  1116. $('#' + checkboxID).prop('disabled', true);
  1117. callback(false);
  1118. }
  1119.  
  1120. $('#' + groupClass).change(function(){$('#' + checkboxID).prop('disabled', !this.checked); callback(this.checked);});
  1121. };
  1122.  
  1123.  
  1124. W.app.modeController.model.bind('change:mode', function(model, modeId, context){
  1125. buildLayerItem((sessionStorage[normalizedText]=='true'));
  1126. });
  1127.  
  1128. buildLayerItem(checked);
  1129. };
  1130. }
  1131.  
  1132. function String(){
  1133. this.toTitleCase = function(str){
  1134. return str.replace(/(?:^|\s)\w/g, function(match) {
  1135. return match.toUpperCase();
  1136. });
  1137. };
  1138. }
  1139. }.call(this));

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址