PropertySelectorDialog.js 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. /*
  2. * PropertySelectorDialog.js
  3. *
  4. * @author realor
  5. */
  6. import { Dialog } from './Dialog.js'
  7. import { Controls } from './Controls.js'
  8. import { Tree } from './Tree.js'
  9. import { I18N } from '../i18n/I18N.js'
  10. class PropertySelectorDialog extends Dialog {
  11. constructor(application, options = {}) {
  12. super(options.title || 'title.property_selector')
  13. this.application = application
  14. this.setI18N(this.application.i18n)
  15. this.setSize(700, 600)
  16. this.treeLabel = document.createElement('div')
  17. I18N.set(this.treeLabel, 'innerHTML', options.treeLabel || 'label.selection_by_properties')
  18. this.bodyElem.appendChild(this.treeLabel)
  19. this.treeScrollElem = document.createElement('div')
  20. this.treeScrollElem.className = 'property_selector_scroll'
  21. this.bodyElem.appendChild(this.treeScrollElem)
  22. this.propertyTree = new Tree(this.treeScrollElem)
  23. this.propertyTree.rootsElem.classList.add('property_selector_tree')
  24. this.toolBarElem = document.createElement('div')
  25. this.toolBarElem.className = 'property_selector_toolbar'
  26. this.bodyElem.appendChild(this.toolBarElem)
  27. this.editorView = this.addCodeEditor('prop_sel_editor', 'label.expression', '', { language: 'javascript', height: '40%' })
  28. this.selectValues = options.selectValues === true
  29. this.findPropertiesOnSelection = options.findPropertiesOnSelection || false
  30. this.isValue = false
  31. this.selectedNode = null
  32. this.addButton('accept', 'button.accept', () => {
  33. this.onAccept()
  34. })
  35. this.addButton('cancel', 'button.cancel', () => {
  36. this.onCancel()
  37. })
  38. }
  39. setCode(code) {
  40. const state = this.editorView.state
  41. const tx = state.update({ changes: { from: 0, to: state.doc.length, insert: code } })
  42. this.editorView.dispatch(tx)
  43. }
  44. getCode() {
  45. return this.editorView.state.doc.toString()
  46. }
  47. appendCode(code) {
  48. const state = this.editorView.state
  49. const tx = state.update({ changes: { from: state.doc.length, insert: code } })
  50. this.editorView.dispatch(tx)
  51. let scrollElem = this.editorView.scrollDOM.parentElement.parentElement
  52. scrollElem.scrollTop = scrollElem.scrollHeight
  53. }
  54. onShow() {
  55. this.propertyMap = this.findProperties()
  56. this.propertyTree.clear()
  57. this.updateTree(this.propertyMap, this.propertyTree)
  58. if (this.selectedNode) {
  59. this.selectedNode.removeClass('selected')
  60. this.selectedNode = null
  61. }
  62. this.updateContextButtons()
  63. }
  64. onAccept() {
  65. this.hide()
  66. }
  67. onCancel() {
  68. this.hide()
  69. }
  70. addContextButton(name, label, action) {
  71. return Controls.addButton(this.toolBarElem, name, label, action)
  72. }
  73. updateContextButtons() {}
  74. getSelectedNodePath() {
  75. let path = []
  76. let node = this.selectedNode
  77. while (node !== null) {
  78. path.push(node.value)
  79. node = node.parent
  80. }
  81. return path.reverse()
  82. }
  83. updateTree(value, node) {
  84. if (value instanceof Map) {
  85. const keys = Array.from(value.keys()).sort()
  86. for (let key of keys) {
  87. let subNode = node.addNode(
  88. key,
  89. event => {
  90. event.preventDefault()
  91. this.selectNode(subNode, false)
  92. },
  93. 'property_set'
  94. )
  95. let subValue = value.get(key)
  96. this.updateTree(subValue, subNode)
  97. }
  98. } else if (value instanceof Set) {
  99. const values = Array.from(value.values()).sort()
  100. for (let subValue of values) {
  101. let type = typeof subValue
  102. if (this.selectValues) {
  103. let valueNode = node.addNode(subValue, event => this.selectNode(valueNode, true), type)
  104. } else {
  105. node.addNode(subValue, () => {}, type)
  106. }
  107. }
  108. }
  109. }
  110. findProperties() {
  111. const application = this.application
  112. const roots = this.findPropertiesOnSelection ? application.selection.roots : [application.baseObject]
  113. const propertyMap = new Map()
  114. for (let root of roots) {
  115. root.traverse(object => {
  116. this.addProperties(object.userData, propertyMap)
  117. })
  118. }
  119. return propertyMap
  120. }
  121. addProperties(data, propertyMap) {
  122. for (let key in data) {
  123. let value = data[key]
  124. let type = typeof value
  125. if (type === 'string' || type === 'number' || type === 'boolean') {
  126. let valueSet = propertyMap.get(key)
  127. if (valueSet === undefined || !(valueSet instanceof Set)) {
  128. valueSet = new Set()
  129. propertyMap.set(key, valueSet)
  130. }
  131. valueSet.add(value)
  132. } else if (type === 'object' && value !== null) {
  133. let subPropertyMap = propertyMap.get(key)
  134. if (subPropertyMap === undefined || !(subPropertyMap instanceof Map)) {
  135. subPropertyMap = new Map()
  136. propertyMap.set(key, subPropertyMap)
  137. }
  138. this.addProperties(value, subPropertyMap)
  139. }
  140. }
  141. }
  142. selectNode(node, isValue) {
  143. this.isValue = isValue
  144. if (this.selectedNode) {
  145. this.selectedNode.removeClass('selected')
  146. }
  147. this.selectedNode = node
  148. node.addClass('selected')
  149. this.updateContextButtons()
  150. }
  151. }
  152. export { PropertySelectorDialog }