combo.ex 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  1. defmodule NITRO.Combo do
  2. require NITRO
  3. require Record
  4. def to_list(fld) when is_atom(fld), do: fld
  5. def to_list(fld), do: :unicode.characters_to_list(fld, :unicode)
  6. def new(_name, obj, module, options) do
  7. dom = :proplists.get_value(:dom, options)
  8. feed = :proplists.get_value(:feed, options)
  9. dropDown([], obj, dom, module, feed)
  10. end
  11. def proto(NITRO.comboKey(value: "")), do: []
  12. def proto(NITRO.comboKey(delegate: []) = msg), do: NITRO.Combo.Search.keyUp(msg)
  13. def proto(NITRO.comboScroll(delegate: []) = msg), do: NITRO.Combo.Search.comboScroll(msg)
  14. def proto(NITRO.comboInsert(delegate: []) = msg), do: comboInsert(msg)
  15. def proto(NITRO.comboAdd(delegate: []) = msg), do: comboAdd(msg)
  16. def proto(NITRO.comboModify(delegate: []) = msg), do: comboModify(msg)
  17. def proto(NITRO.comboGroup(delegate: []) = msg), do: comboGroup(msg)
  18. def proto(NITRO.comboDraft(delegate: []) = msg), do: comboDraft(msg)
  19. def proto(NITRO.comboLoader(delegate: []) = msg), do: comboLoader(msg)
  20. def proto(NITRO.comboKey(delegate: module) = msg) do
  21. case has_function(module, :keyUp) do
  22. true -> module.keyUp(msg)
  23. false -> NITRO.Combo.Search.keyUp(msg)
  24. end
  25. end
  26. def proto(NITRO.comboScroll(delegate: module) = msg) do
  27. case has_function(module, :comboScroll) do
  28. true -> module.comboScroll(msg)
  29. false -> NITRO.Combo.Search.comboScroll(msg)
  30. end
  31. end
  32. def proto(NITRO.comboSelect(delegate: module) = msg) do
  33. case has_function(module, :select) do
  34. true -> module.select(msg)
  35. false -> select(msg)
  36. end
  37. end
  38. def proto(NITRO.comboInsert(delegate: module) = msg) do
  39. case has_function(module, :comboInsert) do
  40. true -> module.comboInsert(msg)
  41. false -> comboInsert(msg)
  42. end
  43. end
  44. def proto(NITRO.comboAdd(delegate: module) = msg) do
  45. case has_function(module, :comboAdd) do
  46. true -> module.comboAdd(msg)
  47. false -> comboAdd(msg)
  48. end
  49. end
  50. def proto(NITRO.comboVecAdd(delegate: module) = msg) do
  51. case has_function(module, :comboVecAdd) do
  52. true -> module.comboVecAdd(msg)
  53. false -> comboVecAdd(msg)
  54. end
  55. end
  56. def proto(NITRO.comboModify(delegate: module) = msg) do
  57. case has_function(module, :comboModify) do
  58. true -> module.comboModify(msg)
  59. false -> comboModify(msg)
  60. end
  61. end
  62. def proto(NITRO.comboGroup(delegate: module) = msg) do
  63. case has_function(module, :comboGroup) do
  64. true -> module.comboGroup(msg)
  65. false -> comboGroup(msg)
  66. end
  67. end
  68. def proto(NITRO.comboDraft(delegate: module) = msg) do
  69. case has_function(module, :comboDraft) do
  70. true -> module.comboDraft(msg)
  71. false -> comboDraft(msg)
  72. end
  73. end
  74. def proto(NITRO.comboLoader(delegate: module) = msg) do
  75. case has_function(module, :comboLoader) do
  76. true -> module.comboLoader(msg)
  77. false -> comboLoader(msg)
  78. end
  79. end
  80. def select(NITRO.comboSelect(uid: uid, dom: field, value: value, delegate: m, update: NITRO.comboUpdate() = update)) do
  81. send(self(), {:direct, NITRO.comboUpdate(update, value: value)})
  82. send(self(), {:direct, NITRO.comboLoader(dom: field, delegate: m, status: :finished)})
  83. NITRO.Combo.Search.stop(uid, field)
  84. end
  85. def select(NITRO.comboSelect(uid: uid, dom: field, delegate: m)) do
  86. send(self(), {:direct, NITRO.comboLoader(dom: field, delegate: m, status: :finished)})
  87. NITRO.Combo.Search.stop(uid, field)
  88. end
  89. def comboInsert(NITRO.comboInsert(chunks: 0, dom: field, status: :finished)) do
  90. :nitro.wire("activeCombo = undefined; currentItem = undefined;")
  91. :nitro.hide(:nitro.atom([:comboContainer, :nitro.to_list(field)]))
  92. :nitro.wire("comboOpenFormById('#{:nitro.atom([:nitro.to_list(field), 'form'])}');")
  93. end
  94. def comboInsert(NITRO.comboInsert(uid: uid, dom: field, rows: rows, delegate: module, feed: feed)) do
  95. :lists.foreach(fn row ->
  96. :nitro.insert_bottom(
  97. :nitro.atom([:comboContainer, :nitro.to_list(field)]),
  98. :nitro.render(dropDown0(uid, row, :nitro.to_list(field), module, feed))
  99. )
  100. end, rows)
  101. end
  102. def comboAdd(NITRO.comboAdd(list_id: list, value: value, bind: bind, delegate: module, pos: pos, feed: feed, default: default)) do
  103. :nitro.insert_bottom(
  104. list,
  105. NITRO.comboLookupModify_item(list_id: list, value: value, bind: bind, pos: pos, feed: feed, delegate: module, default: default)
  106. )
  107. end
  108. def comboVecAdd(NITRO.comboVecAdd(list_id: list, value: value, delegate: mod, feed: feed)), do:
  109. :nitro.wire("appendItemFromBind('#{list}', '#{view_value(value, mod, feed)}', '#{:base64.encode(:erlang.term_to_binary(value))}');")
  110. def comboModify(NITRO.comboModify(list_id: list, item_id: item, value: value, bind: bind, modify_bind: modify_bind, delegate: module, pos: pos, feed: feed)) do
  111. new_bind = :erlang.setelement(pos, bind, modify_bind)
  112. :nitro.update(
  113. item,
  114. NITRO.comboLookupModify_item(list_id: list, value: value, bind: new_bind, pos: pos, feed: feed, delegate: module)
  115. )
  116. end
  117. def comboGroup(NITRO.comboGroup(dom: dom, value: value, delegate: module)) do
  118. :nitro.insert_bottom(
  119. dom,
  120. NITRO.comboLookupGroup_item(value: view_value(value, module, []), bind: value, group: :draft)
  121. )
  122. end
  123. def comboDraft(NITRO.comboDraft(values: [])), do: []
  124. def comboDraft(NITRO.comboDraft(dom: dom, list: list_id, values: values, group: group, subtitle: subtitle, delegate: module)) do
  125. value_pairs = {:view_value_pairs, :lists.map(fn val -> {view_value(val, module, []), val} end, values)}
  126. proto_item = NITRO.comboLookupGroup_list(subtitle: subtitle, delegate: module)
  127. draft_id = :nitro.atom([dom, :draft])
  128. case group do
  129. :draft ->
  130. :nitro.update(draft_id, NITRO.comboLookupGroup_list(proto_item, id: draft_id, group: :draft))
  131. :nitro.insert_bottom(dom, NITRO.comboLookupGroup_list(proto_item, id: :nitro.atom([dom, guid()]), values: value_pairs, group: :saved))
  132. _ ->
  133. :nitro.update(draft_id, NITRO.comboLookupGroup_list(proto_item, id: draft_id, values: value_pairs, group: :draft))
  134. :nitro.remove(list_id)
  135. end
  136. end
  137. def comboLoader(NITRO.comboLoader(dom: dom, status: :finished)), do: :nitro.remove(:nitro.atom([dom, :loader]))
  138. def comboLoader(NITRO.comboLoader(dom: dom)), do: :nitro.insert_bottom(:nitro.atom([:lookup, dom]), loader(:nitro.atom([dom, :loader])))
  139. def dropDown0(uid, obj, dom0, module, feed) do
  140. case has_function(module, :dropDown) do
  141. true ->
  142. module.dropDown(uid, obj, dom0, feed)
  143. false ->
  144. dropDown(uid, obj, dom0, module, feed)
  145. end
  146. end
  147. def view_value(obj, _, _) when obj in ["", [], :undefined], do: []
  148. def view_value(obj, module, feed) do
  149. case :erlang.function_exported(module, :view_value, 2) do
  150. true ->
  151. module.view_value(obj, feed)
  152. false ->
  153. if has_function(module, :view_value) do
  154. module.view_value(obj)
  155. else
  156. view_value(obj)
  157. end
  158. end
  159. end
  160. def view_value(obj) when obj in ["", [], :undefined], do: []
  161. def view_value(obj), do: :nitro.jse(:erlang.iolist_to_binary(apply(:kvs,:field,[obj, hd(index([]))])))
  162. def dropDown(uid, obj, dom0, module, feed) do
  163. view_value = view_value(obj, module, feed)
  164. dom = :nitro.to_list(dom0)
  165. id = :nitro.jse(:erlang.iolist_to_binary(:nitro.atom([dom, :erlang.element(2, obj)])))
  166. item = :nitro.to_list(item(obj, module))
  167. source = :erlang.iolist_to_binary(feed)
  168. click = :nitro.hte(:nitro.jse("comboSelect('#{uid}', '#{dom}', '#{view_value}', '#{source}', '#{module}', '#{id}')"))
  169. move = :nitro.jse("comboLookupMouseMove('#{dom}')")
  170. NITRO.panel(
  171. id: id,
  172. class: ['dropdown-item'],
  173. bind: :base64.encode(:erlang.term_to_binary(obj)),
  174. onclick: click,
  175. onmousemove: move,
  176. body: [
  177. NITRO.p(body: item)
  178. ]
  179. )
  180. end
  181. def index([]), do: [:name, :id]
  182. def index(module) do
  183. case has_function(module, :index) do
  184. true -> module.index()
  185. false -> index([])
  186. end
  187. end
  188. def item(obj, []), do: view_value(obj)
  189. def item(obj, module) do
  190. case has_function(module, :item) do
  191. true -> module.item(obj)
  192. false -> item(obj, [])
  193. end
  194. end
  195. def loader(id), do:
  196. NITRO.div(
  197. id: id,
  198. class: "search-loader",
  199. body: [NITRO.span(), NITRO.span(), NITRO.span(), NITRO.span(), NITRO.span(), NITRO.span()]
  200. )
  201. def update_comboVec(_parent, dom, feed, module, default, elem) do
  202. vector = view_value(default, module, feed)
  203. clear = "createSortable('##{dom}_list');"
  204. append = :lists.map(fn emp -> bind = emp |> :erlang.term_to_binary |> :base64.encode
  205. "appendItemFromBind('#{dom}_list','#{module.cn(emp)}','#{bind}');" end, vector)
  206. |> :erlang.iolist_to_binary
  207. render = :nitro.render elem
  208. command = "elem = qi('#{dom}'); elem.outerHTML = '#{render}';"
  209. :nitro.wire(command <> append <> clear) # reverse
  210. end
  211. def update_combo(id, feed, module), do: :nitro.update(:nitro.atom([:lookup, id]), NITRO.comboLookup(id: id, feed: feed, delegate: module))
  212. def update_combo_value(dom, value, feed, module) do
  213. view_value = view_value(value, module, feed)
  214. update_combo_value(dom, value, feed, module, view_value)
  215. end
  216. def update_combo_value(dom, value, feed, module, view_value) do
  217. bind = :base64.encode(:erlang.term_to_binary(value))
  218. update_combo(dom, feed, module)
  219. command = "elem = qi('#{dom}'); elem.setAttribute('data-bind', '#{bind}'); elem.value = '#{view_value}';"
  220. :nitro.wire(command)
  221. end
  222. def has_function(m, f) do
  223. functions = apply(m, :module_info, [:exports])
  224. isF = Keyword.get(functions, f, -1)
  225. isF != -1
  226. end
  227. defp guid(m \\ :erp) do case has_function(m, :guid) do true -> m.guid(); false -> [] end end
  228. end