You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

260 lines
7.2 KiB

  1. const OverpassLayer = require('overpass-layer')
  2. const tabs = require('modulekit-tabs')
  3. const natsort = require('natsort')
  4. const state = require('./state')
  5. const Filter = require('overpass-frontend').Filter
  6. const getPathFromJSON = require('./getPathFromJSON')
  7. const CategoryOverpass = require('./CategoryOverpass')
  8. CategoryOverpass.defaultValues.filter = {
  9. title: {
  10. type: 'text',
  11. key: [ 'name', 'name:*', 'operator', 'operator:*', 'ref', 'ref:*' ],
  12. name: '{{ trans("filter:title") }}',
  13. op: 'strsearch',
  14. weight: -1,
  15. show_default: true
  16. }
  17. }
  18. class CategoryOverpassFilter {
  19. constructor (master) {
  20. this.master = master
  21. this.data = this.master.data.filter
  22. this.tabFilter = new tabs.Tab({
  23. id: 'filter'
  24. })
  25. this.master.tools.add(this.tabFilter)
  26. this.tabFilter.header.innerHTML = '<i class="fa fa-filter" aria-hidden="true"></i>'
  27. this.tabFilter.header.title = lang('filter')
  28. this.domFilter = document.createElement('form')
  29. this.tabFilter.content.appendChild(this.domFilter)
  30. this.tabFilter.on('select', () => {
  31. this.formFilter.resize()
  32. this.formFilter.focus()
  33. })
  34. for (var k in this.data) {
  35. let f = this.data[k]
  36. if ('name' in f && typeof f.name === 'string') {
  37. global.currentCategory = this.master
  38. let t = OverpassLayer.twig.twig({ data: f.name, autoescape: true })
  39. f.name = decodeHTML(t.render({}).toString())
  40. } else if (!('name' in f)) {
  41. f.name = lang('tag:' + k)
  42. }
  43. if ('query' in f) {
  44. f.queryTemplate = OverpassLayer.twig.twig({ data: f.query, autoescape: false })
  45. }
  46. if ('values' in f) {
  47. let valueNameTemplate = OverpassLayer.twig.twig({ data: f.valueName || '{{ value }}', autoescape: true })
  48. if (typeof f.values === 'string') {
  49. let valuesTemplate = OverpassLayer.twig.twig({ data: f.values, autoescape: true })
  50. let div = document.createElement('div')
  51. div.innerHTML = valuesTemplate.render(this.master.data)
  52. let options = div.getElementsByTagName('option')
  53. f.values = {}
  54. for (let i = 0; i < options.length; i++) {
  55. let option = options[i]
  56. let k = option.value
  57. f.values[k] = {}
  58. Array.from(option.attributes).forEach(attr => {
  59. f.values[k][attr.name] = attr.value
  60. })
  61. if (option.textContent) {
  62. f.values[k].name = option.textContent
  63. }
  64. }
  65. }
  66. if (Array.isArray(f.values) && f.valueName) {
  67. let newValues = {}
  68. f.values.forEach(value => {
  69. newValues[value] = decodeHTML(valueNameTemplate.render({ value }).toString())
  70. })
  71. f.values = newValues
  72. } else if (typeof f.values === 'object') {
  73. for (var k1 in f.values) {
  74. if (typeof f.values[k1] === 'string') {
  75. let t = OverpassLayer.twig.twig({ data: f.values[k1], autoescape: true })
  76. f.values[k1] = decodeHTML(t.render({}).toString())
  77. } else if (typeof f.values[k1] === 'object') {
  78. if (!('name' in f.values[k1])) {
  79. f.values[k1].name = decodeHTML(valueNameTemplate.render({ value: k1 }).toString())
  80. } else if (f.values[k1].name) {
  81. let t = OverpassLayer.twig.twig({ data: f.values[k1].name, autoescape: true })
  82. f.values[k1].name = decodeHTML(t.render({}))
  83. }
  84. }
  85. }
  86. }
  87. if (!('sort' in f) || (f.sort === 'natsort')) {
  88. let v = {}
  89. let sorter = natsort({ insensitive: true })
  90. let keys = Object.keys(f.values)
  91. keys
  92. .sort((a, b) => {
  93. let weight = (f.values[a].weight || 0) - (f.values[b].weight || 0)
  94. if (weight !== 0) {
  95. return weight
  96. }
  97. return sorter(f.values[a].name, f.values[b].name)
  98. })
  99. .forEach(k => { v[k] = f.values[k] })
  100. f.values = v
  101. }
  102. }
  103. }
  104. let masterOptions = {
  105. 'change_on_input': true
  106. }
  107. if (Object.keys(this.data).length > 1) {
  108. masterOptions['type'] = 'form_chooser'
  109. masterOptions['button:add_element'] = '-- ' + lang('add_filter') + ' --'
  110. masterOptions['order'] = false
  111. }
  112. this.formFilter = new form('filter-' + this.master.id, this.data, masterOptions)
  113. this.formFilter.show(this.domFilter)
  114. this.formFilter.onchange = function () {
  115. let param = JSON.parse(JSON.stringify(this.formFilter.get_data()))
  116. this.applyParam(param)
  117. state.update()
  118. }.bind(this)
  119. this.master.on('setParam', this.setParam.bind(this))
  120. this.master.on('applyParam', this.applyParam.bind(this))
  121. this.master.on('open', this.openCategory.bind(this))
  122. this.master.on('stateGet', this.stateGet.bind(this))
  123. }
  124. setParam (param) {
  125. this.formFilter.set_data(param)
  126. }
  127. applyParam (param) {
  128. this.additionalFilter = []
  129. let kvFilter = []
  130. for (var k in param) {
  131. if (param[k] === null) {
  132. continue
  133. }
  134. var d = this.data[k]
  135. if ('values' in d && param[k] in d.values && typeof d.values[param[k]] === 'object' && 'query' in d.values[param[k]]) {
  136. let f = new Filter(d.values[param[k]].query)
  137. this.additionalFilter.push(f.def)
  138. continue
  139. } else if (d.queryTemplate) {
  140. let f = new Filter(decodeHTML(d.queryTemplate.render({ value: param[k] }).toString()))
  141. this.additionalFilter.push(f.def)
  142. continue
  143. }
  144. var v = {
  145. key: 'key' in d ? d.key : k,
  146. value: param[k],
  147. op: '='
  148. }
  149. if ('op' in d) {
  150. if (d.op === 'has_key_value') {
  151. v = {
  152. key: param[k],
  153. op: 'has_key'
  154. }
  155. } else {
  156. v.op = d.op
  157. }
  158. }
  159. if (Array.isArray(v.key)) {
  160. v = {
  161. "or": v.key.map(
  162. key => {
  163. let v1 = { key, value: v.value, op: v.op }
  164. let m = key.match(/^(.*)\*(.*)/)
  165. if (m) {
  166. v1.key = '^' + m[1] + '.*' + m[2]
  167. v1.keyRegexp = true
  168. }
  169. return [ v1 ]
  170. }
  171. )
  172. }
  173. }
  174. kvFilter.push(v)
  175. }
  176. if (kvFilter.length) {
  177. this.additionalFilter.push(kvFilter)
  178. }
  179. if (this.additionalFilter.length === 0) {
  180. this.additionalFilter = []
  181. } else if (this.additionalFilter.length === 1) {
  182. this.additionalFilter = this.additionalFilter[0]
  183. } else {
  184. this.additionalFilter = { and: this.additionalFilter }
  185. }
  186. this.master.layer.setFilter(this.additionalFilter)
  187. if (!this.tabFilter.isSelected()) {
  188. this.tabFilter.select()
  189. }
  190. }
  191. openCategory () {
  192. this.formFilter.resize()
  193. }
  194. stateGet (param) {
  195. let data = this.formFilter.get_data()
  196. for (var k in data) {
  197. if (data[k]) {
  198. param[k] = data[k]
  199. }
  200. }
  201. }
  202. }
  203. register_hook('category-overpass-init', (category) => {
  204. if (category.data.filter) {
  205. new CategoryOverpassFilter(category)
  206. }
  207. })
  208. function decodeHTML (str) {
  209. return str
  210. .replace(/&#039;/g, '\'')
  211. .replace(/&quot;/g, '"')
  212. .replace(/&gt;/g, '>')
  213. .replace(/&lt;/g, '<')
  214. }