WME Bootstrap

Bootstrap library for custom Waze Map Editor scripts

目前为 2022-12-08 提交的版本。查看 最新版本

此脚本不应直接安装,它是一个供其他脚本使用的外部库。如果您需要使用该库,请在脚本元属性加入:// @require https://update.cn-greasyfork.org/scripts/450160/1126191/WME%20Bootstrap.js

  1. // ==UserScript==
  2. // @name WME Bootstrap
  3. // @version 0.0.10
  4. // @description Bootstrap library for custom Waze Map Editor scripts
  5. // @license MIT License
  6. // @author Anton Shevchuk
  7. // @namespace https://greasyfork.org/users/227648-anton-shevchuk
  8. // @supportURL https://github.com/AntonShevchuk/wme-bootstrap/issues
  9. // @match https://*.waze.com/editor*
  10. // @match https://*.waze.com/*/editor*
  11. // @exclude https://*.waze.com/user/editor*
  12. // @icon https://t3.gstatic.com/faviconV2?client=SOCIAL&type=FAVICON&fallback_opts=TYPE,SIZE,URL&url=https://anton.shevchuk.name&size=64
  13. // @grant none
  14. // ==/UserScript==
  15.  
  16. /* jshint esversion: 8 */
  17.  
  18. /* global jQuery, W */
  19.  
  20. (function () {
  21. 'use strict'
  22.  
  23. class Bootstrap {
  24. /**
  25. * Bootstrap it once!
  26. */
  27. constructor () {
  28. const sandbox = typeof unsafeWindow !== 'undefined'
  29. const pageWindow = sandbox ? unsafeWindow : window
  30.  
  31. if (!pageWindow.WMEBootstrap) {
  32. pageWindow.WMEBootstrap = true
  33. this.check()
  34. }
  35. }
  36.  
  37. /**
  38. * Check loading process
  39. * @param tries
  40. */
  41. check (tries = 100) {
  42. this.log('try to initialize')
  43. if (W &&
  44. W.map &&
  45. W.model &&
  46. W.model.countries.top &&
  47. W.loginManager.user
  48. ) {
  49. this.init()
  50. this.log('was initialized')
  51. } else if (tries > 0) {
  52. tries--
  53. setTimeout(() => this.check(tries), 500)
  54. } else {
  55. this.log('initialization failed')
  56. }
  57. }
  58.  
  59. /**
  60. * Initial events and handlers
  61. */
  62. init () {
  63. try {
  64. // setup additional handlers
  65. this.setup()
  66. // fire `bootstrap.wme` event
  67. jQuery(document)
  68. .trigger('bootstrap.wme')
  69. // listen all events
  70. jQuery(document)
  71. .on('segment.wme', () => this.log('🛣️ segment.wme'))
  72. .on('segments.wme', () => this.log('🛣️️ segments.wme'))
  73. .on('node.wme', () => this.log('⭐️ node.wme'))
  74. .on('nodes.wme', () => this.log('⭐️ nodes.wme'))
  75. .on('venue.wme', () => this.log('📍️ venue.wme'))
  76. .on('venues.wme', () => this.log('🏬️ venues.wme'))
  77. .on('point.wme', () => this.log('️🏠 point.wme'))
  78. .on('place.wme', () => this.log('🏢️️ place.wme'))
  79. .on('residential.wme', () => this.log('🪧 residential.wme'))
  80. } catch (e) {
  81. console.error(e)
  82. }
  83. }
  84.  
  85. /**
  86. * Setup additional handler for `selectionchanged` event
  87. */
  88. setup () {
  89. W.selectionManager.events.register('selectionchanged', null, (event) => this.handler(event.selected))
  90.  
  91. this.handler(W.selectionManager.getSelectedFeatures())
  92. }
  93.  
  94. /**
  95. * Proxy-handler
  96. * @param {Array} selected
  97. */
  98. handler (selected) {
  99. if (selected.length === 0) {
  100. jQuery(document).trigger('none.wme')
  101. return
  102. }
  103.  
  104. let isSingle = (selected.length === 1)
  105. let models = selected.map(x => x.model)
  106. let model = models[0]
  107.  
  108. switch (true) {
  109. case (model.type === 'node' && isSingle):
  110. this.triggerById('node.wme', 'node-edit-general', model)
  111. break
  112. case (model.type === 'node'):
  113. this.triggerById('nodes.wme', 'node-edit-general', models)
  114. break
  115. case (model.type === 'segment' && isSingle):
  116. this.triggerById('segment.wme', 'segment-edit-general', model)
  117. break
  118. case (model.type === 'segment'):
  119. this.triggerByQuery('segments.wme', '#segment-edit-general', '#segment-edit-general .feature-ids-details', models)
  120. break
  121. case (model.type === 'venue' && isSingle):
  122. this.triggerById('venue.wme', 'venue-edit-general', model)
  123. if (model.isResidential()) {
  124. this.triggerById('residential.wme', 'venue-edit-general', model)
  125. } else if (model.isPoint()) {
  126. this.triggerById('point.wme', 'venue-edit-general', model)
  127. } else {
  128. this.triggerById('place.wme', 'venue-edit-general', model)
  129. }
  130. break
  131. case (model.type === 'venue'):
  132. this.triggerById('venues.wme', 'mergeVenuesCollection', models)
  133. break
  134. }
  135. }
  136.  
  137. /**
  138. * Fire new event with context
  139. * It can be #node-edit-general
  140. * or #segment-edit-general
  141. * or #venue-edit-general
  142. * or #mergeVenuesCollection
  143. * @param {String} event
  144. * @param {String} selector
  145. * @param {Object|Array} models
  146. */
  147. triggerById (event, selector, models) {
  148. this
  149. .waitElementById(selector)
  150. .then(element => jQuery(document).trigger(event, [element, models]))
  151. }
  152.  
  153. /**
  154. * Fire new event with context
  155. * It can be #node-edit-general
  156. * or #segment-edit-general
  157. * or #venue-edit-general
  158. * or #mergeVenuesCollection
  159. * @param {String} event
  160. * @param {String} element
  161. * @param {String} selector
  162. * @param {Object|Array} models
  163. */
  164. triggerByQuery (event, element, selector, models) {
  165. this
  166. .waitElementByQuery(element, selector)
  167. .then(element => jQuery(document).trigger(event, [element, models]))
  168. }
  169.  
  170. /**
  171. * Wait for DOM Element
  172. * @param selector
  173. * @return {Promise<HTMLElement>}
  174. */
  175. waitElementById (selector) {
  176. selector = '#' + selector
  177. return this.waitElementByQuery(selector, selector)
  178. }
  179.  
  180. /**
  181. * Wait for DOM Element
  182. * @param element
  183. * @param selector
  184. * @return {Promise<HTMLElement>}
  185. */
  186. waitElementByQuery (element, selector) {
  187. return new Promise(resolve => {
  188. if (document.querySelector(selector)) {
  189. return resolve(document.querySelector(element))
  190. }
  191.  
  192. const observer = new MutationObserver(mutations => {
  193. if (document.querySelector(selector)) {
  194. resolve(document.querySelector(element))
  195. observer.disconnect()
  196. }
  197. })
  198.  
  199. observer.observe(document.getElementById('edit-panel'), {
  200. childList: true,
  201. subtree: true
  202. })
  203. })
  204. }
  205.  
  206. /**
  207. * Just logger
  208. * @param {String} message
  209. */
  210. log (message) {
  211. console.log('%cBootstrap:%c ' + message, 'color: #0DAD8D; font-weight: bold', 'color: dimgray; font-weight: normal')
  212. }
  213. }
  214.  
  215. new Bootstrap()
  216.  
  217. })()