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.

281 lines
7.8 KiB

  1. const OverpassLayer = require('overpass-layer')
  2. const tabs = require('modulekit-tabs')
  3. const natsort = require('natsort').default
  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. if ('placeholder' in f && typeof f.placeholder === 'string') {
  104. let t = OverpassLayer.twig.twig({ data: f.placeholder, autoescape: true })
  105. f.placeholder = decodeHTML(t.render({}).toString())
  106. }
  107. }
  108. let masterOptions = {
  109. 'change_on_input': true
  110. }
  111. if (Object.keys(this.data).length > 1) {
  112. masterOptions['type'] = 'form_chooser'
  113. masterOptions['button:add_element'] = '-- ' + lang('add_filter') + ' --'
  114. masterOptions['order'] = false
  115. }
  116. this.formFilter = new form('filter-' + this.master.id, this.data, masterOptions)
  117. this.formFilter.show(this.domFilter)
  118. this.formFilter.onchange = () => {
  119. let param = JSON.parse(JSON.stringify(this.formFilter.get_data()))
  120. this.applyParam(param)
  121. state.update()
  122. }
  123. this.master.on('setParam', this.setParam.bind(this))
  124. this.master.on('applyParam', (param) => {
  125. this.applyParam(param)
  126. if (!this.tabFilter.isSelected()) {
  127. this.tabFilter.select()
  128. }
  129. })
  130. this.master.on('open', this.openCategory.bind(this))
  131. this.master.on('stateGet', this.stateGet.bind(this))
  132. }
  133. setParam (param) {
  134. this.formFilter.set_data(param)
  135. }
  136. applyParam (param) {
  137. this.additionalFilter = Object.keys(param).map(k => {
  138. let values = param[k]
  139. let d = this.data[k]
  140. if (values === null) {
  141. return d.emptyQuery
  142. }
  143. if (!Array.isArray(values)) {
  144. values = [ values ]
  145. }
  146. let ret = values.map(value => {
  147. if ('values' in d && value in d.values && typeof d.values[value] === 'object' && 'query' in d.values[value]) {
  148. let f = new Filter(d.values[value].query)
  149. return f.def
  150. } else if (d.queryTemplate) {
  151. let f = new Filter(decodeHTML(d.queryTemplate.render({ value: value }).toString()))
  152. return f.def
  153. }
  154. var v = {
  155. key: 'key' in d ? d.key : k,
  156. value: value,
  157. op: '='
  158. }
  159. if ('op' in d) {
  160. if (d.op === 'has_key_value') {
  161. v = {
  162. key: value,
  163. op: 'has_key'
  164. }
  165. } else {
  166. v.op = d.op
  167. }
  168. }
  169. if (Array.isArray(v.key)) {
  170. v = {
  171. "or": v.key.map(
  172. key => {
  173. let v1 = { key, value: v.value, op: v.op }
  174. let m = key.match(/^(.*)\*(.*)/)
  175. if (m) {
  176. v1.key = '^' + m[1] + '.*' + m[2]
  177. v1.keyRegexp = true
  178. }
  179. return [ v1 ]
  180. }
  181. )
  182. }
  183. }
  184. return [ v ]
  185. }).filter(f => f) // remove null values
  186. switch (ret.length) {
  187. case 0:
  188. return null
  189. case 1:
  190. return ret[0]
  191. default:
  192. return { or: ret }
  193. }
  194. }).filter(f => f) // remove null values
  195. if (this.additionalFilter.length === 0) {
  196. this.additionalFilter = []
  197. } else if (this.additionalFilter.length === 1) {
  198. this.additionalFilter = this.additionalFilter[0]
  199. } else {
  200. this.additionalFilter = { and: this.additionalFilter }
  201. }
  202. this.master.layer.setFilter(this.additionalFilter)
  203. }
  204. openCategory () {
  205. this.formFilter.resize()
  206. let param = JSON.parse(JSON.stringify(this.formFilter.get_data()))
  207. this.applyParam(param)
  208. }
  209. stateGet (param) {
  210. let data = this.formFilter.get_data()
  211. for (var k in data) {
  212. if (data[k]) {
  213. param[k] = data[k]
  214. }
  215. }
  216. }
  217. }
  218. register_hook('category-overpass-init', (category) => {
  219. if (category.data.filter) {
  220. new CategoryOverpassFilter(category)
  221. }
  222. })
  223. function decodeHTML (str) {
  224. if (typeof str === 'undefined') {
  225. return '-- undefined --'
  226. }
  227. return str
  228. .replace(/&#039;/g, '\'')
  229. .replace(/&quot;/g, '"')
  230. .replace(/&gt;/g, '>')
  231. .replace(/&lt;/g, '<')
  232. }