ArgumentForm.js 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. class ArgumentForm extends window.HTMLElement {
  2. setup (json, callback) {
  3. this.setAttribute('class', 'action-arguments')
  4. this.constructTemplate()
  5. this.domTitle.innerText = json.title
  6. this.domIcon.innerHTML = json.icon
  7. this.createDomFormArguments(json.arguments)
  8. this.domBtnStart.onclick = () => {
  9. for (const arg of this.argInputs) {
  10. if (!arg.validity.valid) {
  11. return
  12. }
  13. }
  14. const argvs = this.getArgumentValues()
  15. callback(argvs)
  16. this.remove()
  17. }
  18. this.domBtnCancel.onclick = () => {
  19. this.remove()
  20. }
  21. }
  22. getArgumentValues () {
  23. const ret = []
  24. for (const arg of this.argInputs) {
  25. ret.push({
  26. name: arg.name,
  27. value: arg.value
  28. })
  29. }
  30. return ret
  31. }
  32. constructTemplate () {
  33. const tpl = document.getElementById('tplArgumentForm')
  34. const content = tpl.content.cloneNode(true)
  35. this.appendChild(content)
  36. this.domTitle = this.querySelector('h2')
  37. this.domIcon = this.querySelector('span.icon')
  38. this.domWrapper = this.querySelector('.wrapper')
  39. this.domArgs = this.querySelector('.arguments')
  40. this.domBtnStart = this.querySelector('[name=start]')
  41. this.domBtnCancel = this.querySelector('[name=cancel]')
  42. }
  43. createDomFormArguments (args) {
  44. this.argInputs = []
  45. for (const arg of args) {
  46. this.domArgs.appendChild(this.createDomLabel(arg))
  47. this.domArgs.appendChild(this.createDomSuggestions(arg))
  48. this.domArgs.appendChild(this.createDomInput(arg))
  49. this.domArgs.appendChild(this.createDomDescription(arg))
  50. }
  51. }
  52. createDomLabel (arg) {
  53. const domLbl = document.createElement('label')
  54. const lastChar = arg.title.charAt(arg.title.length - 1)
  55. if (lastChar === '?' || lastChar === '.' || lastChar === ':') {
  56. domLbl.innerHTML = arg.title
  57. } else {
  58. domLbl.innerHTML = arg.title + ':'
  59. }
  60. domLbl.setAttribute('for', arg.name)
  61. return domLbl
  62. }
  63. createDomSuggestions (arg) {
  64. if (typeof arg.suggestions !== 'object' || arg.suggestions.length === 0) {
  65. return document.createElement('span')
  66. }
  67. const ret = document.createElement('datalist')
  68. ret.setAttribute('id', arg.name + '-choices')
  69. for (const suggestion of Object.keys(arg.suggestions)) {
  70. const opt = document.createElement('option')
  71. opt.setAttribute('value', suggestion)
  72. if (typeof arg.suggestions[suggestion] !== 'undefined' && arg.suggestions[suggestion].length > 0) {
  73. opt.innerText = arg.suggestions[suggestion]
  74. }
  75. ret.appendChild(opt)
  76. }
  77. return ret
  78. }
  79. createDomInput (arg) {
  80. let domEl = null
  81. if (arg.choices.length > 0) {
  82. domEl = document.createElement('select')
  83. // select/choice elements don't get an onchange/validation because theoretically
  84. // the user should only select from a dropdown of valid options. The choices are
  85. // riggeriously checked on StartAction anyway. ValidateArgumentType is only
  86. // meant for showing simple warnings in the UI before running.
  87. for (const choice of arg.choices) {
  88. domEl.appendChild(this.createSelectOption(choice))
  89. }
  90. } else {
  91. switch (arg.type) {
  92. case 'confirmation':
  93. this.domBtnStart.disabled = true
  94. domEl = document.createElement('input')
  95. domEl.setAttribute('type', 'checkbox')
  96. domEl.onchange = () => {
  97. this.domBtnStart.disabled = false
  98. domEl.disabled = true
  99. }
  100. break
  101. case 'raw_string_multiline':
  102. domEl = document.createElement('textarea')
  103. domEl.setAttribute('rows', '5')
  104. domEl.style.resize = 'vertical'
  105. break
  106. case 'datetime':
  107. domEl = document.createElement('input')
  108. domEl.setAttribute('type', 'datetime-local')
  109. domEl.setAttribute('step', '1')
  110. break
  111. case 'password':
  112. case 'email':
  113. domEl = document.createElement('input')
  114. domEl.setAttribute('type', arg.type)
  115. break
  116. default:
  117. domEl = document.createElement('input')
  118. if (arg.type.startsWith('regex:')) {
  119. domEl.setAttribute('pattern', arg.type.replace('regex:', ''))
  120. }
  121. domEl.onchange = () => {
  122. const validateArgumentTypeArgs = {
  123. value: domEl.value,
  124. type: arg.type
  125. }
  126. window.fetch(window.restBaseUrl + 'ValidateArgumentType', {
  127. method: 'POST',
  128. headers: {
  129. 'Content-Type': 'application/json'
  130. },
  131. body: JSON.stringify(validateArgumentTypeArgs)
  132. }).then((res) => {
  133. if (res.ok) {
  134. return res.json()
  135. } else {
  136. throw new Error(res.statusText)
  137. }
  138. }).then((json) => {
  139. if (json.valid) {
  140. domEl.setCustomValidity('')
  141. } else {
  142. domEl.setCustomValidity(json.description)
  143. }
  144. })
  145. }
  146. }
  147. }
  148. domEl.name = arg.name
  149. domEl.value = arg.defaultValue
  150. if (typeof arg.suggestions === 'object' && Object.keys(arg.suggestions).length > 0) {
  151. domEl.setAttribute('list', arg.name + '-choices')
  152. }
  153. this.argInputs.push(domEl)
  154. return domEl
  155. }
  156. createDomDescription (arg) {
  157. const domArgumentDescription = document.createElement('span')
  158. domArgumentDescription.classList.add('argument-description')
  159. domArgumentDescription.innerHTML = arg.description
  160. return domArgumentDescription
  161. }
  162. createSelectOption (choice) {
  163. const domEl = document.createElement('option')
  164. domEl.setAttribute('value', choice.value)
  165. domEl.innerText = choice.title
  166. return domEl
  167. }
  168. }
  169. window.customElements.define('argument-form', ArgumentForm)