WME Switch Uturns

Switches U-turns for selected node or segment. Forked and improved "WME Add Uturn from node" script.

  1. // ==UserScript==
  2. // @name WME Switch Uturns
  3. // @version 2025.03.17.002
  4. // @description Switches U-turns for selected node or segment. Forked and improved "WME Add Uturn from node" script.
  5. // @author ixxvivxxi, uranik, turbopirate, AntonShevchuk
  6. // @namespace https://greatest.deepsurf.us/users/160654-waze-ukraine
  7. // @match https://*.waze.com/editor*
  8. // @match https://*.waze.com/*/editor*
  9. // @exclude https://*.waze.com/user/editor*
  10. // @icon data:image/png;base64,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JD9NIZcD3s/omzJA/y3Qs+b21tzH6QOQoq4SN8DBITCSp+x1j3d3tff275lmfz+vBXK/GI2+FAAADXppVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+Cjx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IlhNUCBDb3JlIDQuNC4wLUV4aXYyIj4KIDxyZGY6UkRGIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyI+CiAgPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIKICAgIHhtbG5zOnhtcE1NPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvbW0vIgogICAgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIKICAgIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIKICAgIHhtbG5zOkdJTVA9Imh0dHA6Ly93d3cuZ2ltcC5vcmcveG1wLyIKICAgIHhtbG5zOnRpZmY9Imh0dHA6Ly9ucy5hZG9iZS5jb20vdGlmZi8xLjAvIgogICAgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIgogICB4bXBNTTpEb2N1bWVudElEPSJnaW1wOmRvY2lkOmdpbXA6NjhjZGRhYmMtYzdiNi00YWRmLWFiOGYtMWFmNzAzOTdhZjc0IgogICB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOjU4NmI4ZWUwLTQ3NTMtNDY0Yy1hNjhlLWYwODMyOWFkZDQ0MiIKICAgeG1wTU06T3JpZ2luYWxEb2N1bWVudElEPSJ4bXAuZGlkOjAwM2VhNDhmLTJiNDgtNGQ4ZC04ZTVlLTdjNjI0ZmY2MjI1ZSIKICAgZGM6Rm9ybWF0PSJpbWFnZS9wbmciCiAgIEdJTVA6QVBJPSIyLjAiCiAgIEdJTVA6UGxhdGZvcm09Ik1hYyBPUyIKICAgR0lNUDpUaW1lU3RhbXA9IjE2NzIyMTk0MDI2MTQ2MzAiCiAgIEdJTVA6VmVyc2lvbj0iMi4xMC4zMiIKICAgdGlmZjpPcmllbnRhdGlvbj0iMSIKICAgeG1wOkNyZWF0b3JUb29sPSJHSU1QIDIuMTAiCiAgIHhtcDpNZXRhZGF0YURhdGU9IjIwMjI6MTI6MjhUMTA6MjM6MjIrMDE6MDAiCiAgIHhtcDpNb2RpZnlEYXRlPSIyMDIyOjEyOjI4VDEwOjIzOjIyKzAxOjAwIj4KICAgPHhtcE1NOkhpc3Rvcnk+CiAgICA8cmRmOlNlcT4KICAgICA8cmRmOmxpCiAgICAgIHN0RXZ0OmFjdGlvbj0ic2F2ZWQiCiAgICAgIHN0RXZ0OmNoYW5nZWQ9Ii8iCiAgICAgIHN0RXZ0Omluc3RhbmNlSUQ9InhtcC5paWQ6YzgwZjNjNDUtNmYxYS00ODlmLTlkYTUtYmJlM2JiYTNhOGVhIgogICAgICBzdEV2dDpzb2Z0d2FyZUFnZW50PSJHaW1wIDIuMTAgKE1hYyBPUykiCiAgICAgIHN0RXZ0OndoZW49IjIwMjItMTItMjhUMTA6MjM6MjIrMDE6MDAiLz4KICAgIDwvcmRmOlNlcT4KICAgPC94bXBNTTpIaXN0b3J5PgogIDwvcmRmOkRlc2NyaXB0aW9uPgogPC9yZGY6UkRGPgo8L3g6eG1wbWV0YT4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIAo8P3hwYWNrZXQgZW5kPSJ3Ij8+NKPOngAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB+YMHAkXFi1wXVEAAAx8SURBVHja5Zt5WNTX1cc/Mwyzsg2E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
  11. // @grant none
  12. // @require https://update.greatest.deepsurf.us/scripts/450160/1218867/WME-Bootstrap.js
  13. // @require https://update.greatest.deepsurf.us/scripts/452563/1218878/WME.js
  14. // @require https://update.greatest.deepsurf.us/scripts/450221/1137043/WME-Base.js
  15. // @require https://update.greatest.deepsurf.us/scripts/450320/1555446/WME-UI.js
  16. // ==/UserScript==
  17.  
  18. /* jshint esversion: 8 */
  19. /* global require */
  20. /* global $, jQuery */
  21. /* global W */
  22. /* global I18n */
  23. /* global WME, WMEBase, WMEUI, WMEUIHelper, WMEUIHelperTab, WMEUIShortcut */
  24.  
  25. (function () {
  26. 'use strict'
  27.  
  28. // Script name, uses as unique index
  29. const NAME = 'SWITCH-UTURNS'
  30.  
  31. // Translations
  32. const TRANSLATION = {
  33. 'en': {
  34. title: 'Switch U-Turns',
  35. description: 'Choose a segment or a node to switch u-turns with <a href="#keyboard-dialog" target="_blank" rel="noopener noreferrer" data-toggle="modal">Keyboard shortcuts</a> or buttons',
  36. count: 'Count nodes and U-Turns',
  37. switch: 'Switch U-turn at point',
  38. nodes: 'Nodes',
  39. allowed: 'Allowed',
  40. disallowed: 'Disallowed',
  41. allow: 'Allow all U-turns',
  42. disallow: 'Disallow all U-turns',
  43. },
  44. 'uk': {
  45. title: 'Керування розворотами',
  46. description: 'Оберіть сегмент або вузол щоб змінити розвороти за допомогою <a href="#keyboard-dialog" target="_blank" rel="noopener noreferrer" data-toggle="modal">гарячих клавіш</a> або кнопок',
  47. count: 'Порахувати вузли та розвороти',
  48. switch: 'Змінити розворот у вузлі',
  49. nodes: 'Вузли',
  50. allowed: 'Дозволено',
  51. disallowed: 'Заборонено',
  52. allow: 'Дозволити всі розвороти',
  53. disallow: 'Заборонити всі розвороти',
  54. },
  55. 'ru': {
  56. title: 'Управление разворотами',
  57. description: 'Выберите сегмент или узел для изменения разворотов с помощью <a href="#keyboard-dialog" target="_blank" rel="noopener noreferrer" data-toggle="modal">комбинаций клавиш</a> или кнопок',
  58. count: 'Посчитать узлы и развороты',
  59. switch: 'Изменить разворот в узле',
  60. nodes: 'Узлы',
  61. allowed: 'Разрешено',
  62. disallowed: 'Запрещено',
  63. allow: 'Разрешить все развороты',
  64. disallow: 'Запретить все развороты',
  65. }
  66. }
  67.  
  68. const STYLE =
  69. 'p.switch-uturns-counter { margin-top: 15px; padding-left: 15px; }' +
  70. 'p.switch-uturns-info { border-top: 1px solid #ccc; color: #777; font-size: x-small; margin-top: 15px; padding-top: 10px; text-align: center; }'
  71.  
  72. WMEUI.addTranslation(NAME, TRANSLATION)
  73. WMEUI.addStyle(STYLE)
  74.  
  75. const ALLOW = 1
  76. const DISALLOW = 0
  77.  
  78. class UTurns extends WMEBase {
  79. constructor (name, settings = null) {
  80. super(name, settings)
  81.  
  82. /** @type {WMEUIHelper} */
  83. this.helper = new WMEUIHelper(this.name)
  84.  
  85. /** @type {WMEUIHelperTab} */
  86. this.tab = this.helper.createTab(
  87. I18n.t(this.name).title,
  88. {
  89. image: GM_info.script.icon
  90. }
  91. )
  92. this.tab.addText('description', I18n.t(this.name).description)
  93. let button = this.tab.addButton(NAME, I18n.t(name).count, '', () => this.updateTabUI(this.countUturns()))
  94. button.html().className += ' waze-btn-blue'
  95.  
  96. this.tab.addText('counter', '')
  97. this.tab.addText(
  98. 'info',
  99. '<a href="' + GM_info.scriptUpdateURL + '">' + GM_info.script.name + '</a> ' + GM_info.script.version
  100. )
  101. // Inject custom HTML to container in the WME interface
  102. this.tab.inject()
  103. }
  104. /**
  105. * Handler for `node.wme` event
  106. * @param {jQuery.Event} event
  107. * @param {HTMLElement} element
  108. * @param {W.model} model
  109. * @return {void}
  110. */
  111. onNode (event, element, model) {
  112. if (model.getSegmentIds().length < 2 || !model.isGeometryEditable()) {
  113. return
  114. }
  115. this.removePanel(element)
  116. this.createPanel(element)
  117. this.updateNodeUI()
  118. }
  119.  
  120. /**
  121. * Added controls
  122. * @param {HTMLElement} element
  123. */
  124. createPanel (element) {
  125. // Container
  126. let container = document.createElement('div')
  127. container.id = NAME
  128. // Separator space
  129. container.append(document.createElement('hr'))
  130. // Title
  131. let title = document.createElement('p')
  132. title.innerText = I18n.t(NAME).title
  133. container.append(title)
  134. // Text
  135. this.text = document.createElement('p')
  136. container.append(this.text)
  137. // Allow button
  138. this.allow = document.createElement('wz-button')
  139. this.allow.color = 'shadowed'
  140. this.allow.innerText = I18n.t(NAME).allow
  141. this.allow.onclick = () => this.switchNodeUturn(ALLOW)
  142. container.append(this.allow)
  143. // Disallow button
  144. this.disallow = document.createElement('wz-button')
  145. this.disallow.color = 'shadowed'
  146. this.disallow.innerText = I18n.t(NAME).disallow
  147. this.disallow.onclick = () => this.switchNodeUturn(DISALLOW)
  148. container.append(this.disallow)
  149.  
  150. element.parentNode.append(container)
  151. }
  152.  
  153. /**
  154. * Remove controls
  155. * @param {HTMLElement} element
  156. */
  157. removePanel(element) {
  158. element.parentNode.querySelector('#' + NAME)?.remove()
  159. }
  160.  
  161. /**
  162. * Update counter for the plugin tab
  163. * @param {Object} counter
  164. */
  165. updateTabUI (counter) {
  166. this.tab.html().querySelector('p.switch-uturns-counter').innerHTML = '' +
  167. I18n.t(NAME).nodes + ': ' + counter.nodes + '<br/>' +
  168. I18n.t(NAME).allowed + ': ' + counter.allowed + '<br/>' +
  169. I18n.t(NAME).disallowed + ': ' + counter.disallowed
  170. }
  171.  
  172. /**
  173. * Updated buttons status and counters
  174. */
  175. updateNodeUI () {
  176. let node = WME.getSelectedNode()
  177. if (!node
  178. || node.getSegmentIds().length < 2
  179. || !node.isGeometryEditable()) {
  180. return
  181. }
  182. let counter = this.countNodeUturns(node)
  183.  
  184. // Change display properties of the buttons
  185. this.allow.style.display = counter.disallowed ? 'flex' : 'none'
  186. this.disallow.style.display = counter.allowed ? 'flex' : 'none'
  187.  
  188. // Change text
  189. this.text.innerHTML =
  190. I18n.t(NAME).allowed + ': ' + counter.allowed + '<br/>' +
  191. I18n.t(NAME).disallowed + ': ' + counter.disallowed
  192. }
  193.  
  194. /**
  195. * @return {{nodes: number, allowed: number, disallowed: number}}
  196. */
  197. countUturns () {
  198. let counters = {
  199. nodes: 0,
  200. allowed: 0,
  201. disallowed: 0
  202. }
  203. for (let node in W.model.nodes.objects) {
  204. let counter = this.countNodeUturns(W.model.nodes.objects[node])
  205. counters.nodes++
  206. counters.allowed += counter.allowed
  207. counters.disallowed += counter.disallowed
  208. }
  209. return counters
  210. }
  211.  
  212. /**
  213. * @param {Object} node
  214. * @return {{allowed: number, disallowed: number}}
  215. */
  216. countNodeUturns (node) {
  217. let counter = {
  218. allowed: 0,
  219. disallowed: 0
  220. }
  221.  
  222. let segmentsIds = node.getSegmentIds()
  223.  
  224. for (let i = 0; i < segmentsIds.length; i++) {
  225. let segment = W.model.segments.getObjectById(segmentsIds[i])
  226. if (!segment) {
  227. continue
  228. }
  229. if (segment.isTurnAllowed(segment, node)) {
  230. counter.allowed++
  231. } else {
  232. counter.disallowed++
  233. }
  234. }
  235. return counter
  236. }
  237.  
  238. /**
  239. * Handler for selected node
  240. * @param {Number} status ALLOW or DISALLOW
  241. */
  242. switchNodeUturn (status) {
  243. let node = WME.getSelectedNode()
  244. if (!node) {
  245. return
  246. }
  247. let segmentsIds = node.getSegmentIds()
  248. if (segmentsIds.length < 2) {
  249. return
  250. }
  251. for (let i = 0; i < segmentsIds.length; i++) {
  252. let segment = W.model.segments.getObjectById(segmentsIds[i])
  253. if (segment.isOneWay()) {
  254. continue;
  255. }
  256. let turn = W.model.getTurnGraph().getTurnThroughNode(node, segment, segment)
  257. W.model.actionManager.add(
  258. new WazeActionSetTurn(
  259. W.model.getTurnGraph(),
  260. turn.withTurnData(turn.getTurnData().withState(status)))
  261. )
  262. }
  263. this.updateNodeUI()
  264.  
  265. this.log('u-turns in the node with ID ' + node.getID() + ' switched to ' + (status ? 'ALLOW' : 'DISALLOW'))
  266. }
  267.  
  268. /**
  269. * Handler for selected segments
  270. * @param direction
  271. */
  272. switchSegmentUturn (direction = 'A') {
  273. let segments = WME.getSelectedSegments()
  274. for (let i = 0, total = segments.length; i < total; i++) {
  275. let segment = segments[i]
  276. if (segment.isOneWay()) {
  277. continue;
  278. }
  279. let node = (direction === 'A') ? segment.getFromNode() : segment.getToNode()
  280. let status = segment.isTurnAllowed(segment, node) ? DISALLOW : ALLOW
  281. let turn = W.model.getTurnGraph().getTurnThroughNode(node, segment, segment)
  282. W.model.actionManager.add(
  283. new WazeActionSetTurn(
  284. W.model.getTurnGraph(),
  285. turn.withTurnData(turn.getTurnData().withState(status)) // enable it
  286. )
  287. )
  288.  
  289. this.log('u-turn in the point ' + direction + ' switched to ' + (status ? 'ALLOW' : 'DISALLOW'))
  290. }
  291. }
  292. }
  293.  
  294. let WazeActionSetTurn
  295.  
  296. $(document)
  297. .on('bootstrap.wme', () => {
  298. // Require Waze components
  299. WazeActionSetTurn = require('Waze/Model/Graph/Actions/SetTurn')
  300.  
  301. let UTurnsInstance = new UTurns(NAME)
  302.  
  303. // Hotkeys for node manipulation
  304. WMEUI.addShortcut(NAME + '-node-allow', I18n.t(NAME).allow, NAME, I18n.t(NAME).title, 'A+A', () => UTurnsInstance.switchNodeUturn(1))
  305. WMEUI.addShortcut(NAME + '-node-disallow', I18n.t(NAME).disallow, NAME, I18n.t(NAME).title, 'A+S', () => UTurnsInstance.switchNodeUturn(0))
  306. // Hotkeys for segment manipulation
  307. WMEUI.addShortcut(NAME + '-segment-a', I18n.t(NAME).switch + ' A', NAME, I18n.t(NAME).title, 'A+Q', () => UTurnsInstance.switchSegmentUturn('A'))
  308. WMEUI.addShortcut(NAME + '-segment-b', I18n.t(NAME).switch + ' B', NAME, I18n.t(NAME).title, 'A+W', () => UTurnsInstance.switchSegmentUturn('B'))
  309. // Update count of UTurns on events
  310. W.model.actionManager.events.register('afterundoaction', null, () => UTurnsInstance.updateNodeUI())
  311. W.model.actionManager.events.register('afterclearactions', null, () => UTurnsInstance.updateNodeUI())
  312. W.model.actionManager.events.register('afteraction', null, () => UTurnsInstance.updateNodeUI())
  313. })
  314. })()