WazeWrap

A base library for WME script writers

当前为 2017-01-30 提交的版本,查看 最新版本

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

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

QingJ © 2025

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