WazeWrapBeta

A base library for WME script writers

当前为 2018-01-09 提交的版本,查看 最新版本

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

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

QingJ © 2025

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