WazeWrap Beta

A base library for WME script writers

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

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

  1. // ==UserScript==
  2. // @name WazeWrap Beta
  3. // @namespace https://gf.qytechs.cn/users/30701-justins83-waze
  4. // @version 0.1.10
  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 WazeWrapBeta */
  15. var WazeWrapBeta = {};
  16.  
  17. (function() {
  18.  
  19. function bootstrap(tries) {
  20. tries = tries || 1;
  21. if (window.W &&
  22. window.W.map &&
  23. window.W.model &&
  24. window.W.loginManager &&
  25. $) {
  26. init();
  27. } else if (tries < 1000) {
  28. setTimeout(function () { bootstrap(tries++); }, 200);
  29. } else {
  30. console.log('WazeWrap failed to load');
  31. }
  32. }
  33.  
  34. bootstrap();
  35.  
  36. function init(){
  37. console.log("WazeWrapBeta initializing...");
  38. var oldLib = window.WazeWrap;
  39. var root = this;
  40.  
  41. WazeWrapBeta .Version = GM_info.script.version;
  42. WazeWrapBeta .isBetaEditor = /beta/.test(location.href);
  43.  
  44. SetUpRequire();
  45.  
  46. WazeWrapBeta .test = "test";
  47. WazeWrapBeta .Geometry = new Geometry;
  48. WazeWrapBeta .Model = new Model;
  49. WazeWrapBeta .Interface = new Interface;
  50. WazeWrapBeta .User = new User;
  51. WazeWrapBeta .Util = new Util;
  52. WazeWrapBeta.Require = new Require;
  53. root.WazeWrapBeta = WazeWrapBeta ;
  54.  
  55. console.log('WazeWrapBeta Loaded');
  56. };
  57.  
  58.  
  59. function SetUpRequire(){
  60. //if(this.isBetaEditor || typeof window.require !== "undefined")
  61. // return;
  62.  
  63. console.log("Setting d2's require fix...");
  64.  
  65. // setup one global var and put all in
  66. var WMEAPI = {};
  67.  
  68. // detect URL of WME source code
  69. WMEAPI.scripts = document.getElementsByTagName('script');
  70.  
  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.  
  105. WMEAPI.t = function (n) {
  106. if (WMEAPI.s[n]) return WMEAPI.s[n].exports;
  107. var r = WMEAPI.s[n] = {
  108. exports: {},
  109. id: n,
  110. loaded: !1
  111. };
  112. return WMEAPI.e[n].call(r.exports, r, r.exports, WMEAPI.t), r.loaded = !0, r.exports;
  113. };
  114.  
  115. // e is a copy of all WME funcs because function t need to access to this list
  116. WMEAPI.e=[];
  117. console.log("1");
  118. // the patch
  119. window.webpackJsonp = function(a, i) {
  120. // our API but we will use it only to build the require stuffs
  121. var api={};
  122. // taken from WME code. a is [1], so...
  123. 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;
  124. console.log("2");
  125. var unknownCount=0;
  126. var classname, funcStr;
  127. console.log("0.1.10");
  128. // copy i in e and keep a link from classname to index in e
  129. for (o in i){
  130. WMEAPI.e[o] = i[o];
  131. funcStr = i[o].toString();
  132. classname = funcStr.match(/CLASS_NAME:\"([^\"]*)\"/);
  133. if (classname){
  134. // keep the link.
  135. api[classname[1].replace(/\./g,'/').replace(/^W\//, 'Waze/')]={index: o, func: WMEAPI.e[o]};
  136. }
  137. else{
  138. api['Waze/Unknown/' + unknownCount]={index: o, func: WMEAPI.e[o]};
  139. unknownCount++;
  140. }
  141. }
  142. console.log("3");
  143. // taken from WME code: it calls the original webpackJsonp and do something else, but I don't really know what.
  144. // removed the call to the original webpackJsonp: still works...
  145. //for (tmp && tmp(a, i); l.length;) l.shift().call(null, t);
  146. for (; l.length;) l.shift().call(null, WMEAPI.t);
  147. WMEAPI.s[0] = 0;
  148. // run the first func of WME. This first func will call recusrsively all funcs needed to setup the API.
  149. // After this call, s will contain all instanciables classes.
  150. //var ret = WMEAPI.t(0);
  151. // now, build the requires thanks to the link we've built in var api.
  152. var module={};
  153. var apiFuncName;
  154. unknownCount=0;
  155. console.log("4");
  156. for (o in i){
  157. funcStr = i[o].toString();
  158. classname = funcStr.match(/CLASS_NAME:\"([^\"]*)\"/);
  159. if (classname){
  160. module={};
  161. apiFuncName = classname[1].replace(/\./g,'/').replace(/^W\//, 'Waze/');
  162. module[apiFuncName]=WMEAPI.t(api[apiFuncName].index);
  163. WMEAPI.require.define(module);
  164. }
  165. else{
  166. var matches = funcStr.match(/SEGMENT:"segment",/);
  167. if (matches){
  168. module={};
  169. apiFuncName='Waze/Model/ObjectType';
  170. module[apiFuncName]=WMEAPI.t(api['Waze/Unknown/' + unknownCount].index);
  171. WMEAPI.require.define(module);
  172. }
  173. unknownCount++;
  174. }
  175. }
  176. console.log("5");
  177.  
  178. // restore the original func
  179. window.webpackJsonp=WMEAPI.tmp;
  180. console.log("6");
  181. // set the require public if needed
  182. // if so: others scripts must wait for the window.require to be available before using it.
  183. WazeWrapBeta.require = WMEAPI.require;
  184. console.log(WMEAPI.require);
  185. console.log(WazeWrapBeta.require);
  186. // all available functions are in WMEAPI.require.define.modules
  187. // console.debug this variable to read it:
  188. // console.debug('Modules: ', WMEAPI.require.define.modules);
  189. // run your script here:
  190. // setTimeout(yourscript);
  191. // again taken from WME code. Not sure about what it does.
  192. //if (i[0]) return ret;
  193. };
  194.  
  195. // some kind of global vars and init
  196. WMEAPI.s = {};
  197. WMEAPI.r = {
  198. 0: 0
  199. };
  200.  
  201. // hacking finished
  202.  
  203. // load again WME through our patched func
  204. WMEAPI.WMEHACK_Injected_script = document.createElement("script");
  205. WMEAPI.WMEHACK_Injected_script.setAttribute("type", "application/javascript");
  206. WMEAPI.WMEHACK_Injected_script.src = WMEAPI.url;
  207. document.body.appendChild(WMEAPI.WMEHACK_Injected_script);
  208. console.log("d2 fix complete");
  209. }
  210.  
  211. function Geometry(){
  212. //var geometry = WazeWrap.Geometry;
  213.  
  214. //Converts to "normal" GPS coordinates
  215. this.ConvertTo4326 = function (long, lat){
  216. var projI=new OpenLayers.Projection("EPSG:900913");
  217. var projE=new OpenLayers.Projection("EPSG:4326");
  218. return (new OpenLayers.LonLat(long, lat)).transform(projI,projE);
  219. };
  220. this.ConvertTo900913 = function (long, lat){
  221. var projI=new OpenLayers.Projection("EPSG:900913");
  222. var projE=new OpenLayers.Projection("EPSG:4326");
  223. return (new OpenLayers.LonLat(long, lat)).transform(projE,projI);
  224. };
  225.  
  226. //Converts the Longitudinal offset to an offset in 4326 gps coordinates
  227. this.CalculateLongOffsetGPS = function(longMetersOffset, long, lat)
  228. {
  229. var R= 6378137; //Earth's radius
  230. var dLon = longMetersOffset / (R * Math.cos(Math.PI * lat / 180)); //offset in radians
  231. var lon0 = dLon * (180 / Math.PI); //offset degrees
  232.  
  233. return lon0;
  234. };
  235.  
  236. //Converts the Latitudinal offset to an offset in 4326 gps coordinates
  237. this.CalculateLatOffsetGPS = function(latMetersOffset, lat)
  238. {
  239. var R= 6378137; //Earth's radius
  240. var dLat = latMetersOffset/R;
  241. var lat0 = dLat * (180 /Math.PI); //offset degrees
  242.  
  243. return lat0;
  244. };
  245. /**
  246. * Checks if the given geometry is on screen
  247. * @function WazeWrap.Model.isGeometryInMapExtent
  248. * @param {OpenLayers.Geometry} Geometry to check if any part of is in the current viewport
  249. */
  250. this.isLonLatInMapExtent = function (lonLat) {
  251. 'use strict';
  252. return lonLat && W.map.getExtent().containsLonLat(lonLat);
  253. };
  254. /**
  255. * Checks if the given geometry is on screen
  256. * @function WazeWrap.Model.isGeometryInMapExtent
  257. * @param {OpenLayers.Geometry} Geometry to check if any part of is in the current viewport
  258. */
  259. this.isGeometryInMapExtent = function (geometry) {
  260. 'use strict';
  261. return geometry && geometry.getBounds &&
  262. W.map.getExtent().intersectsBounds(geometry.getBounds());
  263. };
  264. /**
  265. * Calculates the distance between two given points
  266. * @function WazeWrap.Model.calculateDistance
  267. * @param {OpenLayers.Geometry.Point} An array of OL.Geometry.Point with which to measure the total distance. A minimum of 2 points is needed.
  268. */
  269. this.calculateDistance = function(pointArray) {
  270. if(pointArray.length < 2)
  271. return 0;
  272.  
  273. var line = new OpenLayers.Geometry.LineString(pointArray);
  274. length = line.getGeodesicLength(W.map.getProjectionObject());
  275. return length; //multiply by 3.28084 to convert to feet
  276. };
  277.  
  278. this.findClosestSegment = function(mygeometry){
  279. var onscreenSegments = WazeWrapBeta.Model.getOnscreenSegments();
  280. var minDistance = Infinity;
  281. var closestSegment;
  282. for (s in onscreenSegments) {
  283. if (!onscreenSegments.hasOwnProperty(s))
  284. continue;
  285.  
  286. segmentType = onscreenSegments[s].attributes.roadType;
  287. if (segmentType === 10 || segmentType === 3 || segmentType === 16 || segmentType === 18 || segmentType === 19) //10 ped boardwalk, 16 stairway, 18 railroad, 19 runway, 3 freeway
  288. continue;
  289.  
  290. distanceToSegment = mygeometry.distanceTo(onscreenSegments[s].geometry, {details: true});
  291.  
  292. if (distanceToSegment.distance < minDistance) {
  293. minDistance = distanceToSegment.distance;
  294. closestSegment = onscreenSegments[s];//.seg = s;
  295. //closestSegment.point = new OL.Geometry.Point(distanceToSegment.x1, distanceToSegment.y1);
  296. }
  297. }
  298. return closestSegment;
  299. };
  300. };
  301.  
  302. function Model(){
  303.  
  304. this.getPrimaryStreetID = function(segmentID){
  305. return W.model.segments.get(segmentID).attributes.primaryStreetID;
  306. };
  307.  
  308. this.getStreetName = function(primaryStreetID){
  309. return W.model.streets.get(PrimaryStreetID).name;
  310. };
  311.  
  312. this.getCityID = function(primaryStreetID){
  313. return W.model.streets.get(primaryStreetID).cityID;
  314. };
  315.  
  316. this.getCityName = function(primaryStreetID){
  317. return W.model.cities.get(this.getCityID(primaryStreetID)).attributes.Name;
  318. };
  319.  
  320. this.getStateName = function(primaryStreetID){
  321. return W.model.states.get(getStateID(primaryStreetID)).Name;
  322. };
  323.  
  324. this.getStateID = function(primaryStreetID){
  325. return W.model.cities.get(primaryStreetID).attributes.stateID;
  326. };
  327.  
  328. this.getCountryID = function(primaryStreetID){
  329. return W.model.cities.get(this.getCityID(primaryStreetID)).attributes.CountryID;
  330. };
  331.  
  332. this.getCountryName = function(primaryStreetID){
  333. return W.model.countries.get(getCountryID(primaryStreetID)).name;
  334. };
  335.  
  336. this.getCityNameFromSegmentObj = function(segObj){
  337. return this.getCityName(segObj.attributes.primaryStreetID);
  338. };
  339.  
  340. this.getStateNameFromSegmentObj = function(segObj){
  341. return this.getStateName(segObj.attributes.primaryStreetID);
  342. };
  343.  
  344. //returns an array of segmentIDs for all segments that are part of the same roundabout as the passed segment
  345. this.getAllRoundaboutSegmentsFromObj = function(segObj){
  346. if(segObj.model.attributes.junctionID === null)
  347. return null;
  348.  
  349. return W.model.junctions.objects[segObj.model.attributes.junctionID].segIDs;
  350. };
  351.  
  352. this.getAllRoundaboutJunctionNodesFromObj = function(segObj){
  353. var RASegs = this.getAllRoundaboutSegmentsFromObj(segObj);
  354. var RAJunctionNodes = [];
  355. for(i=0; i< RASegs.length; i++){
  356. RAJunctionNodes.push(W.model.nodes.objects[W.model.segments.get(RASegs[i]).attributes.toNodeID]);
  357.  
  358. }
  359. return RAJunctionNodes;
  360. };
  361.  
  362. this.isRoundaboutSegmentID = function(segmentID){
  363. if(W.model.segments.get(segmentID).attributes.junctionID === null)
  364. return false;
  365. else
  366. return true;
  367. };
  368.  
  369. this.isRoundaboutSegmentObj = function(segObj){
  370. if(segObj.model.attributes.junctionID === null)
  371. return false;
  372. else
  373. return true;
  374. };
  375.  
  376.  
  377. this.getOnscreenSegments = function(){
  378. var segments = W.model.segments.objects;
  379. var mapExtent = W.map.getExtent();
  380. var onScreenSegments = [];
  381. var seg;
  382.  
  383. for (s in segments) {
  384. if (!segments.hasOwnProperty(s))
  385. continue;
  386.  
  387. seg = W.model.segments.get(s);
  388. if (mapExtent.intersectsBounds(seg.geometry.getBounds()))
  389. onScreenSegments.push(seg);
  390. }
  391. return onScreenSegments;
  392. };
  393.  
  394. /**
  395. * Defers execution of a callback function until the WME map and data
  396. * model are ready. Call this function before calling a function that
  397. * causes a map and model reload, such as W.map.moveTo(). After the
  398. * move is completed the callback function will be executed.
  399. * @function WazeWrap.Model.onModelReady
  400. * @param {Function} callback The callback function to be executed.
  401. * @param {Boolean} now Whether or not to call the callback now if the
  402. * model is currently ready.
  403. * @param {Object} context The context in which to call the callback.
  404. */
  405. this.onModelReady = function (callback, now, context) {
  406. var deferModelReady = function () {
  407. return $.Deferred(function (dfd) {
  408. var resolve = function () {
  409. dfd.resolve();
  410. W.model.events.unregister('mergeend', null, resolve);
  411. };
  412. W.model.events.register('mergeend', null, resolve);
  413. }).promise();
  414. };
  415. var deferMapReady = function () {
  416. return $.Deferred(function (dfd) {
  417. var resolve = function () {
  418. dfd.resolve();
  419. W.vent.off('operationDone', resolve);
  420. };
  421. W.vent.on('operationDone', resolve);
  422. }).promise();
  423. };
  424.  
  425. if (typeof callback === 'function') {
  426. context = context || callback;
  427. if (now && WazeWrapBeta.Util.mapReady() && WazeWrapBeta.Util.modelReady()) {
  428. callback.call(context);
  429. } else {
  430. $.when(deferMapReady() && deferModelReady()).
  431. then(function () {
  432. callback.call(context);
  433. });
  434. }
  435. }
  436. };
  437. };
  438. function User(){
  439. this.Rank = function(){
  440. return W.loginManager.user.normalizedLevel;
  441. };
  442.  
  443. this.Username = function(){
  444. return W.loginManager.user.userName;
  445. };
  446.  
  447. this.isCM = function(){
  448. if(W.loginManager.user.editableCountryIDs.length > 0)
  449. return true;
  450. else
  451. return false;
  452. };
  453. this.isAM = function(){
  454. return W.loginManager.user.isAreaManager;
  455. };
  456. };
  457.  
  458.  
  459. function Require(){
  460.  
  461. this.DragElement = function(){
  462. var myDragElement = OL.Class({
  463. started: !1,
  464. stopDown: !0,
  465. dragging: !1,
  466. touch: !1,
  467. last: null ,
  468. start: null ,
  469. lastMoveEvt: null ,
  470. oldOnselectstart: null ,
  471. interval: 0,
  472. timeoutId: null ,
  473. forced: !1,
  474. active: !1,
  475. initialize: function(e) {
  476. this.map = e,
  477. this.uniqueID = myDragElement.baseID--
  478. },
  479. callback: function(e, t) {
  480. if (this[e])
  481. return this[e].apply(this, t)
  482. },
  483. dragstart: function(e) {
  484. e.xy = new OL.Pixel(e.clientX - this.map.viewPortDiv.offsets[0],e.clientY - this.map.viewPortDiv.offsets[1]);
  485. var t = !0;
  486. return this.dragging = !1,
  487. (OL.Event.isLeftClick(e) || OL.Event.isSingleTouch(e)) && (this.started = !0,
  488. this.start = e.xy,
  489. this.last = e.xy,
  490. OL.Element.addClass(this.map.viewPortDiv, "olDragDown"),
  491. this.down(e),
  492. this.callback("down", [e.xy]),
  493. OL.Event.stop(e),
  494. this.oldOnselectstart || (this.oldOnselectstart = document.onselectstart ? document.onselectstart : OL.Function.True),
  495. document.onselectstart = OL.Function.False,
  496. t = !this.stopDown),
  497. t
  498. },
  499. forceStart: function() {
  500. var e = arguments.length > 0 && void 0 !== arguments[0] && arguments[0];
  501. return this.started = !0,
  502. this.endOnMouseUp = e,
  503. this.forced = !0,
  504. this.last = {
  505. x: 0,
  506. y: 0
  507. },
  508. this.callback("force")
  509. },
  510. forceEnd: function() {
  511. if (this.forced)
  512. return this.endDrag()
  513. },
  514. dragmove: function(e) {
  515. return this.map.viewPortDiv.offsets && (e.xy = new OL.Pixel(e.clientX - this.map.viewPortDiv.offsets[0],e.clientY - this.map.viewPortDiv.offsets[1])),
  516. this.lastMoveEvt = e,
  517. !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)),
  518. this.dragging = !0,
  519. this.move(e),
  520. this.oldOnselectstart || (this.oldOnselectstart = document.onselectstart,
  521. document.onselectstart = OL.Function.False),
  522. this.last = e.xy),
  523. !0
  524. },
  525. dragend: function(e) {
  526. if (e.xy = new OL.Pixel(e.clientX - this.map.viewPortDiv.offsets[0],e.clientY - this.map.viewPortDiv.offsets[1]),
  527. this.started) {
  528. var t = this.start !== this.last;
  529. this.endDrag(),
  530. this.up(e),
  531. this.callback("up", [e.xy]),
  532. t && this.callback("done", [e.xy])
  533. }
  534. return !0
  535. },
  536. endDrag: function() {
  537. this.started = !1,
  538. this.dragging = !1,
  539. this.forced = !1,
  540. OL.Element.removeClass(this.map.viewPortDiv, "olDragDown"),
  541. document.onselectstart = this.oldOnselectstart
  542. },
  543. down: function(e) {},
  544. move: function(e) {},
  545. up: function(e) {},
  546. out: function(e) {},
  547. mousedown: function(e) {
  548. return this.dragstart(e)
  549. },
  550. touchstart: function(e) {
  551. return this.touch || (this.touch = !0,
  552. this.map.events.un({
  553. mousedown: this.mousedown,
  554. mouseup: this.mouseup,
  555. mousemove: this.mousemove,
  556. click: this.click,
  557. scope: this
  558. })),
  559. this.dragstart(e)
  560. },
  561. mousemove: function(e) {
  562. return this.dragmove(e)
  563. },
  564. touchmove: function(e) {
  565. return this.dragmove(e)
  566. },
  567. removeTimeout: function() {
  568. if (this.timeoutId = null ,
  569. this.dragging)
  570. return this.mousemove(this.lastMoveEvt)
  571. },
  572. mouseup: function(e) {
  573. if (!this.forced || this.endOnMouseUp)
  574. return this.started ? this.dragend(e) : void 0
  575. },
  576. touchend: function(e) {
  577. if (e.xy = this.last,
  578. !this.forced)
  579. return this.dragend(e)
  580. },
  581. click: function(e) {
  582. return this.start === this.last
  583. },
  584. activate: function(e) {
  585. this.$el = e,
  586. this.active = !0;
  587. var t = $(this.map.viewPortDiv);
  588. return this.$el.on("mousedown.drag-" + this.uniqueID, $.proxy(this.mousedown, this)),
  589. this.$el.on("touchstart.drag-" + this.uniqueID, $.proxy(this.touchstart, this)),
  590. $(document).on("mouseup.drag-" + this.uniqueID, $.proxy(this.mouseup, this)),
  591. t.on("mousemove.drag-" + this.uniqueID, $.proxy(this.mousemove, this)),
  592. t.on("touchmove.drag-" + this.uniqueID, $.proxy(this.touchmove, this)),
  593. t.on("touchend.drag-" + this.uniqueID, $.proxy(this.touchend, this))
  594. },
  595. deactivate: function() {
  596. return this.active = !1,
  597. this.$el.off(".drag-" + this.uniqueID),
  598. $(this.map.viewPortDiv).off(".drag-" + this.uniqueID),
  599. $(document).off(".drag-" + this.uniqueID),
  600. this.touch = !1,
  601. this.started = !1,
  602. this.forced = !1,
  603. this.dragging = !1,
  604. this.start = null ,
  605. this.last = null ,
  606. OL.Element.removeClass(this.map.viewPortDiv, "olDragDown")
  607. },
  608. adjustXY: function(e) {
  609. var t = OL.Util.pagePosition(this.map.viewPortDiv);
  610. return e.xy.x -= t[0],
  611. e.xy.y -= t[1]
  612. },
  613. CLASS_NAME: "W.Handler.DragElement"
  614. });
  615. myDragElement.baseID = 0;
  616. };
  617. };
  618. function Util(){
  619. /**
  620. * Function to defer function execution until an element is present on
  621. * the page.
  622. * @function WazeWrap.Util.waitForElement
  623. * @param {String} selector The CSS selector string or a jQuery object
  624. * to find before executing the callback.
  625. * @param {Function} callback The function to call when the page
  626. * element is detected.
  627. * @param {Object} [context] The context in which to call the callback.
  628. */
  629. this.waitForElement = function (selector, callback, context) {
  630. var jqObj;
  631.  
  632. if (!selector || typeof callback !== 'function') {
  633. return;
  634. }
  635.  
  636. jqObj = typeof selector === 'string' ?
  637. $(selector) : selector instanceof $ ? selector : null;
  638.  
  639. if (!jqObj.size()) {
  640. window.requestAnimationFrame(function () {
  641. WazeWrapBeta.Util.waitForElement(selector, callback, context);
  642. });
  643. } else {
  644. callback.call(context || callback);
  645. }
  646. };
  647.  
  648. /**
  649. * Function to track the ready state of the map.
  650. * @function WazeWrap.Util.mapReady
  651. * @return {Boolean} Whether or not a map operation is pending or
  652. * undefined if the function has not yet seen a map ready event fired.
  653. */
  654. this.mapReady = function () {
  655. var mapReady = true;
  656. W.vent.on('operationPending', function () {
  657. mapReady = false;
  658. });
  659. W.vent.on('operationDone', function () {
  660. mapReady = true;
  661. });
  662. return function () {
  663. return mapReady;
  664. };
  665. } ();
  666.  
  667. /**
  668. * Function to track the ready state of the model.
  669. * @function WazeWrap.Util.modelReady
  670. * @return {Boolean} Whether or not the model has loaded objects or
  671. * undefined if the function has not yet seen a model ready event fired.
  672. */
  673. this.modelReady = function () {
  674. var modelReady = true;
  675. W.model.events.register('mergestart', null, function () {
  676. modelReady = false;
  677. });
  678. W.model.events.register('mergeend', null, function () {
  679. modelReady = true;
  680. });
  681. return function () {
  682. return modelReady;
  683. };
  684. } ();
  685. };
  686.  
  687. function Interface() {
  688. /**
  689. * Generates id for message bars.
  690. * @private
  691. */
  692. var getNextID = function () {
  693. var id = 1;
  694. return function () {
  695. return id++;
  696. };
  697. } ();
  698. this.Shortcut = OL.Class(this, /** @lends WazeWrap.Interface.Shortcut.prototype */ {
  699. name: null,
  700. group: null,
  701. shortcut: {},
  702. callback: null,
  703. scope: null,
  704. groupExists: false,
  705. actionExists: false,
  706. eventExists: false,
  707. defaults: {
  708. group: 'default'
  709. },
  710. /**
  711. * Creates a new {WazeWrap.Interface.Shortcut}.
  712. * @class
  713. * @name WazeWrap.Interface.Shortcut
  714. * @param name {String} The name of the shortcut.
  715. * @param group {String} The name of the shortcut group.
  716. * @param shortcut {String} The shortcut key(s). The shortcut
  717. * should be of the form 'i' where i is the keyboard shortuct or
  718. * include modifier keys such as 'CSA+i', where C = the control
  719. * key, S = the shift key, A = the alt key, and i = the desired
  720. * keyboard shortcut. The modifier keys are optional.
  721. * @param callback {Function} The function to be called by the
  722. * shortcut.
  723. * @param scope {Object} The object to be used as this by the
  724. * callback.
  725. * @return {WazeWrap.Interface.Shortcut} The new shortcut object.
  726. * @example //Creates new shortcut and adds it to the map.
  727. * shortcut = new WazeWrap.Interface.Shortcut('myName', 'myGroup', 'C+p', callbackFunc, null).add();
  728. */
  729. initialize: function (name, group, shortcut, callback, scope) {
  730. if ('string' === typeof name && name.length > 0 &&
  731. 'string' === typeof shortcut && shortcut.length > 0 &&
  732. 'function' === typeof callback) {
  733. this.name = name;
  734. this.group = group || this.defaults.group;
  735. this.callback = callback;
  736. this.shortcut[shortcut] = name;
  737. if ('object' !== typeof scope) {
  738. this.scope = null;
  739. } else {
  740. this.scope = scope;
  741. }
  742. return this;
  743. }
  744. },
  745. /**
  746. * Determines if the shortcut's group already exists.
  747. * @private
  748. */
  749. doesGroupExist: function () {
  750. this.groupExists = 'undefined' !== typeof W.accelerators.Groups[this.group] &&
  751. undefined !== typeof W.accelerators.Groups[this.group].members &&
  752. W.accelerators.Groups[this.group].length > 0;
  753. return this.groupExists;
  754. },
  755. /**
  756. * Determines if the shortcut's action already exists.
  757. * @private
  758. */
  759. doesActionExist: function () {
  760. this.actionExists = 'undefined' !== typeof W.accelerators.Actions[this.name];
  761. return this.actionExists;
  762. },
  763. /**
  764. * Determines if the shortcut's event already exists.
  765. * @private
  766. */
  767. doesEventExist: function () {
  768. this.eventExists = 'undefined' !== typeof W.accelerators.events.listeners[this.name] &&
  769. W.accelerators.events.listeners[this.name].length > 0 &&
  770. this.callback === W.accelerators.events.listeners[this.name][0].func &&
  771. this.scope === W.accelerators.events.listeners[this.name][0].obj;
  772. return this.eventExists;
  773. },
  774. /**
  775. * Creates the shortcut's group.
  776. * @private
  777. */
  778. createGroup: function () {
  779. W.accelerators.Groups[this.group] = [];
  780. W.accelerators.Groups[this.group].members = [];
  781. },
  782. /**
  783. * Registers the shortcut's action.
  784. * @private
  785. */
  786. addAction: function () {
  787. W.accelerators.addAction(this.name, { group: this.group });
  788. },
  789. /**
  790. * Registers the shortcut's event.
  791. * @private
  792. */
  793. addEvent: function () {
  794. W.accelerators.events.register(this.name, this.scope, this.callback);
  795. },
  796. /**
  797. * Registers the shortcut's keyboard shortcut.
  798. * @private
  799. */
  800. registerShortcut: function () {
  801. W.accelerators._registerShortcuts(this.shortcut);
  802. },
  803. /**
  804. * Adds the keyboard shortcut to the map.
  805. * @return {WazeWrap.Interface.Shortcut} The keyboard shortcut.
  806. */
  807. add: function () {
  808. /* If the group is not already defined, initialize the group. */
  809. if (!this.doesGroupExist()) {
  810. this.createGroup();
  811. }
  812.  
  813. /* Clear existing actions with same name */
  814. if (this.doesActionExist()) {
  815. W.accelerators.Actions[this.name] = null;
  816. }
  817. this.addAction();
  818.  
  819. /* Register event only if it's not already registered */
  820. if (!this.doesEventExist()) {
  821. this.addEvent();
  822. }
  823.  
  824. /* Finally, register the shortcut. */
  825. this.registerShortcut();
  826. return this;
  827. },
  828. /**
  829. * Removes the keyboard shortcut from the map.
  830. * @return {WazeWrap.Interface.Shortcut} The keyboard shortcut.
  831. */
  832. remove: function () {
  833. if (this.doesEventExist()) {
  834. W.accelerators.events.unregister(this.name, this.scope, this.callback);
  835. }
  836. if (this.doesActionExist()) {
  837. delete W.accelerators.Actions[this.name];
  838. }
  839. //remove shortcut?
  840. return this;
  841. },
  842. /**
  843. * Changes the keyboard shortcut and applies changes to the map.
  844. * @return {WazeWrap.Interface.Shortcut} The keyboard shortcut.
  845. */
  846. change: function (shortcut) {
  847. if (shortcut) {
  848. this.shortcut = {};
  849. this.shortcut[shortcut] = this.name;
  850. this.registerShortcut();
  851. }
  852. return this;
  853. }
  854. }),
  855.  
  856. this.Tab = OL.Class(this, {
  857. /** @lends WazeWrap.Interface.Tab */
  858. TAB_SELECTOR: '#user-tabs ul.nav-tabs',
  859. CONTENT_SELECTOR: '#user-info div.tab-content',
  860. callback: null,
  861. $content: null,
  862. context: null,
  863. $tab: null,
  864. /**
  865. * Creates a new WazeWrap.Interface.Tab. The tab is appended to the WME
  866. * editor sidebar and contains the passed HTML content.
  867. * @class
  868. * @name WazeWrap.Interface.Tab
  869. * @param {String} name The name of the tab. Should not contain any
  870. * special characters.
  871. * @param {String} content The HTML content of the tab.
  872. * @param {Function} [callback] A function to call upon successfully
  873. * appending the tab.
  874. * @param {Object} [context] The context in which to call the callback
  875. * function.
  876. * @return {WazeWrap.Interface.Tab} The new tab object.
  877. * @example //Creates new tab and adds it to the page.
  878. * new WazeWrap.Interface.Tab('thebestscriptever', '<div>Hello World!</div>');
  879. */
  880. initialize: function (name, content, callback, context) {
  881. var idName, i = 0;
  882. if (name && 'string' === typeof name &&
  883. content && 'string' === typeof content) {
  884. if (callback && 'function' === typeof callback) {
  885. this.callback = callback;
  886. this.context = context || callback;
  887. }
  888. /* Sanitize name for html id attribute */
  889. idName = name.toLowerCase().replace(/[^a-z-_]/g, '');
  890. /* Make sure id will be unique on page */
  891. while (
  892. $('#sidepanel-' + (i ? idName + i : idName)).length > 0) {
  893. i++;
  894. }
  895. if (i) {
  896. idName = idName + i;
  897. }
  898. /* Create tab and content */
  899. this.$tab = $('<li/>')
  900. .append($('<a/>')
  901. .attr({
  902. 'href': '#sidepanel-' + idName,
  903. 'data-toggle': 'tab',
  904. })
  905. .text(name));
  906. this.$content = $('<div/>')
  907. .addClass('tab-pane')
  908. .attr('id', 'sidepanel-' + idName)
  909. .html(content);
  910.  
  911. this.appendTab();
  912. }
  913. },
  914.  
  915. append: function (content) {
  916. this.$content.append(content);
  917. },
  918.  
  919. appendTab: function () {
  920. WazeWrapBeta.Util.waitForElement(
  921. this.TAB_SELECTOR + ',' + this.CONTENT_SELECTOR,
  922. function () {
  923. $(this.TAB_SELECTOR).append(this.$tab);
  924. $(this.CONTENT_SELECTOR).first().append(this.$content);
  925. if (this.callback) {
  926. this.callback.call(this.context);
  927. }
  928. }, this);
  929. },
  930.  
  931. clearContent: function () {
  932. this.$content.empty();
  933. },
  934.  
  935. destroy: function () {
  936. this.$tab.remove();
  937. this.$content.remove();
  938. }
  939. });
  940. };
  941.  
  942. }.call(this));

QingJ © 2025

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