comboLookup.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342
  1. function comboOpenFormById(formId) {
  2. var form = qi(formId);
  3. form && comboOpenForm(form);
  4. }
  5. function comboCloseFormById(formId) {
  6. var form = qi(formId);
  7. form && comboCloseForm(form);
  8. }
  9. function comboOpenForm(container) {
  10. var dropdown = container.parentNode.querySelector('.dropdown');
  11. container.scrollTop = 0;
  12. container.parentNode.classList.add('dropdown-open');
  13. dropdown.classList.add('dropdown-open');
  14. activeForm = container.id;
  15. };
  16. function comboCloseForm(container) {
  17. container.parentNode.classList.remove('dropdown-open');
  18. //container.previousSibling.classList.remove('dropdown-open');
  19. activeForm = undefined;
  20. };
  21. function comboLookupTextApply(dom) {
  22. let elem = qi(dom);
  23. if (elem) {
  24. let textareaSplit = dom.split('_');
  25. textareaSplit.pop();
  26. const textarea = qi(textareaSplit.join('_'));
  27. textarea ? textarea.value = elem.value : null;
  28. }
  29. }
  30. function comboClear(dom) {
  31. let elem = qi('comboContainer_' + dom)
  32. var dropdown = qi(dom).closest('.dropdown');
  33. if (elem) { elem.style.display = 'none' }
  34. dropdown.classList.remove('dropdown-open');
  35. dropdown.classList.remove('is-reversed');
  36. activeCombo = undefined; currentItem = undefined;
  37. }
  38. function comboSelect(uid, dom, row, feed, mod, id) {
  39. let elem = qi(dom);
  40. elem.value = '';
  41. comboClear(dom);
  42. if (qi(elem.getAttribute('nested'))) {
  43. comboSelectNested(...arguments);
  44. } else if (elem.parentNode.parentNode.getAttribute('data-modify-input')) {
  45. comboSelectModify(...arguments);
  46. } else if (elem.parentNode.parentNode.parentNode.getAttribute('data-vector-input')) {
  47. comboSelectVector(...arguments);
  48. } else if (elem.parentNode.parentNode.getAttribute('data-group-input')) {
  49. comboSelectGroup(...arguments);
  50. } else if (elem.parentNode.parentNode.parentNode.getAttribute('data-edit-input') && elem.parentNode.parentNode.parentNode.getAttribute('multiple') === "true") {
  51. comboSelectVector(...arguments); comboCloseFormById(`${dom}_form`);
  52. } else {
  53. comboSelectDefault(...arguments);
  54. }
  55. }
  56. function comboSelectDefault(uid, dom, row, feed, mod, id) {
  57. let elem = qi(dom);
  58. elem.closest('.dropdown').classList.add('dropdown-bind')
  59. elem.value = row;
  60. let value = string(row);
  61. let update = list();
  62. const selected = qi(id);
  63. if (selected) {
  64. elem.setAttribute('data-bind', selected.getAttribute('data-bind'));
  65. value = dec(unbase64(selected.getAttribute('data-bind')));
  66. if (elem.getAttribute('data-update')) { update = dec(unbase64(elem.getAttribute('data-update'))); }
  67. }
  68. direct(tuple(atom('comboSelect'), bin(uid), value, string(dom), string(feed), atom(mod), update));
  69. comboLookupTextApply(dom);
  70. };
  71. function comboSelectNested(uid, dom, row, feed, mod, id) {
  72. const modifyItem = qi(qi(dom).getAttribute('nested'));
  73. const list = modifyItem.parentNode;
  74. const value = qi(id) ? dec(unbase64(qi(id).getAttribute('data-bind'))) : string(row)
  75. direct(tuple(atom('comboModify'),
  76. string(list.id),
  77. string(modifyItem.id),
  78. string(modifyItem.firstChild.innerHTML),
  79. dec(unbase64(modifyItem.getAttribute('data-bind'))),
  80. value,
  81. dec(unbase64(list.getAttribute('data-delegate'))),
  82. dec(unbase64(list.getAttribute('data-pos'))),
  83. dec(unbase64(list.getAttribute('data-feed')))));
  84. }
  85. function comboSelectModify(uid, dom, row, feed, mod, id) {
  86. comboSelectDefault(...arguments);
  87. let listSplit = dom.split('_');
  88. listSplit.pop();
  89. const listId = listSplit.join('_') + '_list';
  90. const input = qi(dom);
  91. const list = qi(listId);
  92. if (list && input && input.value != '') {
  93. const data = querySourceRaw(dom);
  94. if (data && data.hasOwnProperty('text') && data.hasOwnProperty('bind')) {
  95. const bind = data.bind;
  96. const value = data.text;
  97. if (bind !== '' && bind !== 'null') {
  98. clearInput(dom);
  99. direct(tuple(atom('comboAdd'),
  100. string(listId),
  101. string(value),
  102. dec(unbase64(bind)),
  103. dec(unbase64(list.getAttribute('data-delegate'))),
  104. dec(unbase64(list.getAttribute('data-pos'))),
  105. dec(unbase64(list.getAttribute('data-feed'))),
  106. dec(unbase64(list.getAttribute('data-default')))));
  107. }
  108. }
  109. }
  110. }
  111. function comboSelectVector(uid, dom, row, feed, mod, id) {
  112. comboSelectDefault(...arguments);
  113. let listSplit = dom.split('_');
  114. listSplit.pop();
  115. const listId = listSplit.join('_') + '_list';
  116. const input = qi(dom);
  117. const list = qi(listId);
  118. if (list && input && input.value != '') {
  119. const data = querySourceRaw(dom);
  120. if (data && data.hasOwnProperty('text') && data.hasOwnProperty('bind')) {
  121. const bind = data.bind;
  122. const value = data.text;
  123. if (bind !== '' && bind !== 'null') {
  124. clearInput(dom);
  125. direct(tuple(atom('comboVecAdd'), string(listId), dec(unbase64(bind)), string(feed), atom(mod)));
  126. }
  127. }
  128. }
  129. }
  130. function comboSelectGroup(uid, dom, row, feed, mod, id) {
  131. const selected = qi(id);
  132. if (selected) {
  133. const parent = qi(dom).parentNode.parentNode;
  134. const bind = selected.getAttribute('data-bind');
  135. if (!parent.querySelector(`[data-group-item='data-group-item'][data-bind='${bind}']`)) {
  136. const draft = parent.id + '_draft';
  137. const value = dec(unbase64(bind));
  138. const subtitle = qi(draft).querySelector(".group-list__label");
  139. direct(tuple(atom('comboGroup'), string(draft), value, atom(mod), bin(subtitle.textContent), string(parent.id)));
  140. }
  141. }
  142. }
  143. function comboLookupChange(dom) {
  144. let elem = qi(dom);
  145. if (elem && !elem.getAttribute('nested')) {
  146. elem.removeAttribute("data-bind");
  147. const dropdown = qi(dom).closest('.dropdown');
  148. if (dropdown) { dropdown.classList.remove('dropdown-bind'); }
  149. comboLookupTextApply(dom);
  150. }
  151. }
  152. function comboLookupClick(uid, dom, feed, mod) {
  153. var dropdown = qi(dom).closest('.dropdown');
  154. var char = event.which || event.keyCode;
  155. if (char == 1 && !activeCombo && (qi(dom).value == '' || qi(dom).getAttribute('nested'))) {
  156. activeCombo = dom;
  157. currentItem = undefined;
  158. dropdown.classList.add('dropdown-open');
  159. if (window.innerHeight - dropdown.getBoundingClientRect().bottom < 100)
  160. dropdown.classList.add('is-reversed');
  161. direct(tuple(atom('comboKey'),
  162. bin(uid),
  163. bin('all'),
  164. string(dom),
  165. string(feed),
  166. atom(mod)));
  167. return
  168. } else if (char == 1 && activeCombo == dom) { comboClear(dom); }
  169. }
  170. function comboLookupKeydown(uid, dom, feed, mod) {
  171. if (event.key == 'Meta') { return }
  172. if (event.key == 'Alt') { return }
  173. if (event.key == 'Shift') { return }
  174. var dropdown = qi(dom).closest('.dropdown');
  175. var char = event.which || event.keyCode;
  176. if (qi(dom).value == '' && event.key == 'Backspace') { return }
  177. if (char == 40 && !activeCombo && qi(dom).value == '') {
  178. activeCombo = dom;
  179. currentItem = undefined;
  180. dropdown.classList.add('dropdown-open');
  181. if (window.innerHeight - dropdown.getBoundingClientRect().bottom < 100)
  182. dropdown.classList.add('is-reversed');
  183. direct(tuple(atom('comboKey'),
  184. bin(uid),
  185. bin('all'),
  186. string(dom),
  187. string(feed),
  188. atom(mod)));
  189. return
  190. }
  191. if (activeCombo && [35, 36, 38, 40].includes(char)) {
  192. event.preventDefault();
  193. if (char == 40) { set_focus( currentItem && ( !cycleEnabled || currentItem.nextSibling)
  194. ? currentItem.nextSibling : qi('comboContainer_' + dom).firstChild, true) }
  195. if (char == 35) { set_focus( currentItem && ( !cycleEnabled || currentItem.nextSibling)
  196. ? currentItem.parentNode.lastChild : currentItem, true) }
  197. if (char == 38) { set_focus( currentItem && ( !cycleEnabled || currentItem.previousSibling)
  198. ? currentItem.previousSibling : qi('comboContainer_' + dom).lastChild, true) }
  199. if (char == 36) { set_focus( currentItem && ( !cycleEnabled || currentItem.previousSibling)
  200. ? currentItem.parentNode.firstChild : currentItem, true) }
  201. }
  202. if (char == 13) { event.preventDefault(); return }
  203. }
  204. function comboLookupKeyup(uid, dom, feed, mod) {
  205. var dropdown = qi(dom).closest('.dropdown')
  206. if (event.key == 'Meta') { return }
  207. if (event.key == 'Alt') { return }
  208. if (event.key == 'Shift') { return }
  209. if (event.key == 'Tab') { dropdown.classList.remove('dropdown-open'); return }
  210. var char = event.which || event.keyCode;
  211. if (char == 27 || (char == 8 || char == 46) && qi(dom).value == '') {
  212. if(event.key == 'Backspace') {
  213. direct(tuple(atom('comboKey'),
  214. bin(uid),
  215. bin('stop'),
  216. string(dom),
  217. string(feed),
  218. atom(mod)));
  219. }
  220. clearInput(dom); return
  221. }
  222. if (char == 13 && currentItem) { currentItem.click(); return }
  223. if ([33, 34, 37, 39].includes(char)) { return }
  224. if (activeCombo && [35, 36, 38, 40].includes(char)) { return }
  225. else {
  226. activeCombo = dom;
  227. currentItem = undefined;
  228. dropdown.classList.add('dropdown-open');
  229. if (window.innerHeight - dropdown.getBoundingClientRect().bottom < 100)
  230. dropdown.classList.add('is-reversed');
  231. direct(tuple(atom('comboKey'),
  232. bin(uid),
  233. bin(qi(dom).value),
  234. string(dom),
  235. string(feed),
  236. atom(mod)));
  237. }
  238. }
  239. function comboLookupMouseMove(dom) {
  240. set_focus(event.target.closest('.dropdown-item'), false)
  241. }
  242. function set_focus(elem, scroll) {
  243. if (elem) {
  244. if(currentItem) {currentItem.className = "dropdown-item"}
  245. elem.className = "dropdown-item focus"
  246. if (scroll==true) {elem.scrollIntoView({block: "nearest", inline: "nearest"})}
  247. currentItem = elem
  248. }
  249. }
  250. function clearInput(dom) {
  251. const input = qi(dom);
  252. if (input) {
  253. input.value = '';
  254. input.removeAttribute('value');
  255. }
  256. comboLookupChange(dom);
  257. comboClear(dom);
  258. if (input && input.getAttribute('data-update')) {
  259. let update = dec(unbase64(input.getAttribute('data-update')));
  260. update.v[5] = atom('skip');
  261. direct(update);
  262. }
  263. }
  264. function comboLookupModifyValues(listId) {
  265. const list = qi(listId);
  266. if (list) {
  267. return Array.from(list.children).map(function (el) {
  268. return {'text': el.firstChild.innerHTML, 'bind': el.getAttribute('data-bind')}
  269. })
  270. } else {
  271. return []
  272. }
  273. }
  274. function comboLookupGroupDraft(id, group, subtitle, mod) {
  275. const elem = qi(id);
  276. const values = Array.from(elem.querySelectorAll('[data-group-item]')).map(function (el) {return dec(unbase64(el.getAttribute('data-bind')))});
  277. direct(tuple(atom('comboDraft'), string(elem.parentNode.id), string(id), values, atom(group), bin(subtitle), atom(mod)));
  278. }
  279. function groupListDrag(e) { e.dataTransfer.setData('text', e.target.id); }
  280. function groupListDrop(e) {
  281. e.preventDefault();
  282. const node1 = e.currentTarget;
  283. const node2 = qi(e.dataTransfer.getData('text'));
  284. const parent = node1.parentNode;
  285. const sibling = node1.nextSibling === node2 ? node1 : node1.nextSibling;
  286. node2.parentNode.insertBefore(node1, node2);
  287. parent.insertBefore(node2, sibling);
  288. }
  289. function groupListAllowDrop(e) {
  290. e.preventDefault();
  291. e.dataTransfer.dropEffect = 'move';
  292. }
  293. document.addEventListener("click", () => {
  294. if (activeCombo && event.target.className != 'triangle' &&
  295. !event.target.closest('#comboContainer_' + activeCombo)) {
  296. comboClear(activeCombo);
  297. } else if (activeForm && event.target.className != 'triangle' &&
  298. !event.target.closest("#" + activeForm)) {
  299. comboCloseFormById(activeForm);
  300. }
  301. })
  302. function comboLostFocus(e) { }
  303. function comboOnFocus(e) { }
  304. function comboLookupMouseOut(dom) { }
  305. var activeCombo = undefined
  306. var activeForm = undefined
  307. var currentItem = undefined
  308. var cycleEnabled = false