initP5MainMenuDropdown.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346
  1. if (!global.p5UI__MenuStore) throw 'Missing global.p5UI__MenuStore'
  2. var DBG = DBG || 0
  3. var DBG1 = 1
  4. function renderLabel(item) {
  5. return (item.short_label !== item.desc)
  6. ? item.short_label + ' <em>' + item.desc + '</em>'
  7. : item.short_label
  8. ;
  9. }
  10. function renderTitle(item) {
  11. return (item.label !== item.desc)
  12. ? item.label + ' (' + item.desc + ')'
  13. : item.label
  14. ;
  15. }
  16. function renderStar(id, idsBookmarks) {
  17. return (-1 !== idsBookmarks.indexOf(id))
  18. ? '<i class=\"bookmark-item-rem glyphicon glyphicon-star\" title=\"Usuń z ulubionych\" onClick=\"return p5BookmarksRemove(event, ' + id + ')\"></i>'
  19. : '<i class=\"bookmark-item-add glyphicon glyphicon-star-empty\" title=\"Dodaj do ulubionych\" onClick=\"return p5BookmarksAdd(event, ' + id + ')\"></i>'
  20. ;
  21. }
  22. function makeRenderDropdownListItem(grouped, data) {
  23. return function renderDropdownListItem(baseNs) {
  24. var item = (baseNs in grouped.mapNsToIdx)
  25. ? data.objects[ grouped.mapNsToIdx[baseNs] ]
  26. : data.objects[ grouped.mapNsToIdx[ grouped.menuTreeNs[baseNs][0] ] ]
  27. ;
  28. DBG && console.log('DBG:renderP5MainMenuDropdown >> render loop', { baseNs, isInMap: (baseNs in grouped.mapNsToIdx), item, idx: [ grouped.mapNsToIdx[baseNs], grouped.menuTreeNs[baseNs][0] ] });
  29. return (grouped.menuTreeNs[baseNs].length > 1)
  30. ? '<li class="dropdown-submenu">' +
  31. '<a href=\"index.php?_route=ViewTableAjax&namespace=' + item.namespace + '\" title="' + renderTitle(item) + '">' +
  32. renderStar(item.id, data.idsBookmarks) +
  33. ' ' + renderLabel(item) +
  34. '</a>' + "\n" +
  35. '<ul class="dropdown-menu">' +
  36. grouped.menuTreeNs[baseNs].map(function (subItemNs) {
  37. var subItem = data.objects[ grouped.mapNsToIdx[subItemNs] ]
  38. return '<li data-id="' + subItem.id + '">' +
  39. '<a href=\"index.php?_route=ViewTableAjax&namespace=' + subItem.namespace + '\" title="' + renderTitle(subItem) + '">' +
  40. renderStar(subItem.id, data.idsBookmarks) +
  41. ' ' + renderLabel(subItem) +
  42. '</a>' +
  43. '</li>'
  44. ;
  45. }).join("\n") +
  46. '</ul>' +
  47. '</li>' + "\n"
  48. : '<li data-id="' + item.id + '">' +
  49. '<a href=\"index.php?_route=ViewTableAjax&namespace=' + item.namespace + '\" title="' + renderTitle(item) + '">' +
  50. renderStar(item.id, data.idsBookmarks) +
  51. ' ' + renderLabel(item) +
  52. '</a>' +
  53. '</li>' + "\n"
  54. ;
  55. }
  56. }
  57. function renderP5MainMenuDropdown(data) {
  58. DBG && console.log('DBG:renderP5MainMenuDropdown data.objects', data.objects)
  59. var grouped = data.objects.reduce(function (ret, item, idx) {
  60. ret.mapNsToIdx[ item.namespace ] = idx
  61. var nsParts = item.namespace.split('/')
  62. var baseNs = nsParts.slice(0, 2).join('/')
  63. DBG && console.log('DBG:renderP5MainMenuDropdown >> reduce loop ', { nsParts, baseNs });
  64. if (!ret.menuTreeNs[baseNs]) ret.menuTreeNs[baseNs] = []
  65. ret.menuTreeNs[baseNs].push(item.namespace)
  66. return ret;
  67. }, { mapNsToIdx: {}, menuTreeNs: {} })
  68. DBG && console.log('DBG:renderP5MainMenuDropdown grouped', grouped)
  69. var renderDropdownListItem = makeRenderDropdownListItem(grouped, data)
  70. var labels = Object.keys(grouped.menuTreeNs).map(function (baseNs) {
  71. var item = (baseNs in grouped.mapNsToIdx)
  72. ? data.objects[ grouped.mapNsToIdx[baseNs] ]
  73. : data.objects[ grouped.mapNsToIdx[ grouped.menuTreeNs[baseNs][0] ] ]
  74. ;
  75. return {
  76. ns: baseNs,
  77. label: (item.short_label !== item.desc) ? item.short_label : item.desc,
  78. }
  79. });
  80. DBG && console.log('DBG:renderP5MainMenuDropdown labels', labels)
  81. labels.sort(function (item1, item2) {
  82. var l1 = item1.label.toLowerCase()
  83. var l2 = item2.label.toLowerCase()
  84. if (l1 < l2) { return -1; }
  85. if (l1 > l2) { return 1; }
  86. return 0
  87. })
  88. var groupeByLabel = labels.reduce(function (ret, item) {
  89. if (!ret.length) return [ { prefix: item.label, labels: [ item ] } ];
  90. var last = ret.pop()
  91. var labelLast = last.prefix.replace('_', ' ').split(" ")
  92. var labelItem = item.label.replace('_', ' ').split(" ")
  93. DBG && console.log('DBG:renderP5MainMenuDropdown TODO: group?', { last, item, labelLast, labelItem })
  94. if (labelLast[0] === labelItem[0]) {
  95. last.labels.push(item)
  96. last.prefix = labelLast[0] + " <em>(" + last.labels.length + ")</em>"
  97. ret.push(last)
  98. } else {
  99. ret.push(last)
  100. ret.push({ prefix: item.label, labels: [item] })
  101. return ret;
  102. }
  103. return ret;
  104. }, [])
  105. var nodesGroupedByLabel = groupeByLabel.map(function (item) {
  106. // var baseNs =
  107. if (item.labels.length === 1) {
  108. return renderDropdownListItem(item.labels[0].ns)
  109. } else {
  110. // return '<details><summary>' + item.prefix + '</summary><div>' +
  111. // '' + item.labels.map(function (label) {
  112. // return renderDropdownListItem(label.ns)
  113. // }).join("\n") +
  114. // '</div></details>';
  115. return '<li class="dropdown-submenu">' +
  116. '<a href=\"#\" onClick="return false">' +
  117. // '<b style="padding-left:18px">' + item.prefix + '</b>' +
  118. '<i class="glyphicon glyphicon-folder-open" style="opacity:0.5; font-size:90%; padding-right:3px"></i>' + " " +
  119. '<b>' + item.prefix + '</b>' +
  120. '</a>' + "\n" +
  121. '<ul class="dropdown-menu">' +
  122. item.labels.map(function (label) {
  123. return renderDropdownListItem(label.ns);
  124. }).join("\n") +
  125. '</ul>' +
  126. '</li>' + "\n"
  127. ;
  128. }
  129. })
  130. DBG && console.log('DBG:renderP5MainMenuDropdown grouped', { grouped, labels, groupeByLabel })
  131. return nodesGroupedByLabel;
  132. // var jqDropdownMenu = jQuery('#' + idSubMenu)
  133. // jqDropdownMenu.empty()
  134. // jqDropdownMenu.append(searchBox);
  135. // jqDropdownMenu.append(nodesGroupedByLabel);
  136. // var liNodes = Object.keys(grouped.menuTreeNs).map(function (baseNs) {
  137. // var item = (baseNs in grouped.mapNsToIdx)
  138. // ? data.objects[ grouped.mapNsToIdx[baseNs] ]
  139. // : data.objects[ grouped.mapNsToIdx[ grouped.menuTreeNs[baseNs][0] ] ]
  140. // ;
  141. // DBG && console.log('DBG:renderP5MainMenuDropdown >> render loop', { baseNs, isInMap: (baseNs in grouped.mapNsToIdx), item, idx: [ grouped.mapNsToIdx[baseNs], grouped.menuTreeNs[baseNs][0] ] });
  142. // return (grouped.menuTreeNs[baseNs].length > 1)
  143. // ? '<li class="dropdown-submenu">' +
  144. // '<a href=\"index.php?_route=ViewTableAjax&namespace=' + item.namespace + '\" title="' + renderTitle(item) + '">' +
  145. // renderStar(item.id, data.idsBookmarks) +
  146. // ' ' + renderLabel(item) +
  147. // '</a>' + "\n" +
  148. // '<ul class="dropdown-menu">' +
  149. // grouped.menuTreeNs[baseNs].map(function (subItemNs) {
  150. // var subItem = data.objects[ grouped.mapNsToIdx[subItemNs] ]
  151. // return '<li>' +
  152. // '<a href=\"index.php?_route=ViewTableAjax&namespace=' + subItem.namespace + '\" title="' + renderTitle(subItem) + '">' +
  153. // renderStar(subItem.id, data.idsBookmarks) +
  154. // ' ' + renderLabel(subItem) +
  155. // '</a>' +
  156. // '</li>'
  157. // ;
  158. // }).join("\n") +
  159. // '</ul>' +
  160. // '</li>' + "\n"
  161. // : '<li>' +
  162. // '<a href=\"index.php?_route=ViewTableAjax&namespace=' + item.namespace + '\" title="' + renderTitle(item) + '">' +
  163. // renderStar(item.id, data.idsBookmarks) +
  164. // ' ' + renderLabel(item) +
  165. // '</a>' +
  166. // '</li>' + "\n"
  167. // ;
  168. // })
  169. // jqDropdownMenu.append(liNodes);
  170. }
  171. function initP5MainMenuDropdown( btnNode, idSubMenu ) { // @usage: onClick="return initP5MainMenuDropdown(this, 'SE-menu-tables')"
  172. DBG && console.log('DBG:initP5MainMenuDropdown({idSubMenu: '+idSubMenu+'})');
  173. if (!btnNode._initialized) {
  174. var jqDropdownTrigger = jQuery(btnNode)
  175. var jqDropdownMenu = jQuery('#' + idSubMenu)
  176. var jqDropdownParent = jqDropdownMenu.parent()
  177. var idSearchBoxNode = 'idSubMenu_searchBox';
  178. var rerenderDropdown = (function (global, idSubMenu, jqDropdownMenu, jqDropdownTrigger) {
  179. return function (data) {
  180. DBG && console.log('DBG renderP5MainMenuDropdown', {data, idSubMenu});
  181. var query = '';
  182. var searchBox = document.createElement('div')
  183. searchBox.setAttribute('style', "padding:12px 20px");
  184. {
  185. var searchBox_group = document.createElement('div')
  186. searchBox_group.setAttribute('class', "input-group");
  187. {
  188. searchBox_group_icon = document.createElement('span')
  189. searchBox_group_icon.setAttribute('class', "input-group-addon");
  190. searchBox_group_icon.innerHTML = '<i class="glyphicon glyphicon-search" title="Szukaj"></i>';
  191. searchBox_group.appendChild(searchBox_group_icon)
  192. }
  193. {
  194. searchBox_group_input = document.createElement('input')
  195. searchBox_group_input.setAttribute('type', "text");
  196. searchBox_group_input.setAttribute('class', "form-control");
  197. searchBox_group_input.setAttribute('value', query);
  198. searchBox_group_input.setAttribute('id', idSearchBoxNode);
  199. searchBox_group_input.setAttribute('autofocus', "autofocus");
  200. // onChange: function (fieldName, value) {
  201. // priv.options.filterStore.dispatch(priv.options.filterActions.searchBox_delayFilter(fieldName, value));
  202. // }
  203. jQuery(searchBox_group_input).on('keyup', function (event) {
  204. event.preventDefault()
  205. event.stopPropagation()
  206. searchBox_delayFilter(makeMainMenuFilterCallback(jqDropdownMenu, jqDropdownTrigger), event.target.value)
  207. })
  208. searchBox_group.appendChild(searchBox_group_input)
  209. }
  210. searchBox.appendChild(searchBox_group)
  211. jQuery(searchBox).on('click', function (event) {
  212. DBG && console.log("DBG:searchBox.on(click) ...")
  213. event.preventDefault()
  214. event.stopPropagation()
  215. })
  216. }
  217. jqDropdownMenu.empty()
  218. jqDropdownMenu.append(searchBox);
  219. jqDropdownMenu.append(renderP5MainMenuDropdown(data));
  220. }
  221. })(global, idSubMenu, jqDropdownMenu, jqDropdownTrigger);
  222. global.p5UI__MenuStore.subscribe(rerenderDropdown)
  223. jqDropdownTrigger.attr('data-toggle', 'dropdown') // is required by bootstrap dorpdown.js even if is called via js
  224. jqDropdownParent.on('shown.bs.dropdown', function () {
  225. // DBG && console.log("DBG:Main menu:shown.bs.dropdown")
  226. jQuery('#' + idSearchBoxNode).focus()
  227. })
  228. jqDropdownParent.on('hidden.bs.dropdown', function () {
  229. // DBG && console.log("DBG:Main menu:hidden.bs.dropdown")
  230. })
  231. global.p5UI__MenuStore.forceUpdate()
  232. jQuery(btnNode).dropdown()
  233. }
  234. btnNode._initialized = true // TODO: DBG TEST
  235. return true;
  236. }
  237. function menuStore__getObjectById(id) {
  238. var allData = global.p5UI__MenuStore.getData()
  239. if (!allData || !allData.objects) return null;
  240. for (var i = 0, l = allData.objects.length; i < l; i++) {
  241. var itemObj = allData.objects[i]
  242. if (itemObj.id === id) return itemObj;
  243. }
  244. return null;
  245. }
  246. function searchBox__isStringMatch(str, query) {
  247. // TODO: split query for words
  248. return (-1 !== str.toLowerCase().search(query.toLowerCase()));
  249. }
  250. function searchBox__isMenuObjectMatch(itemObj, query) {
  251. if (!itemObj) return false;
  252. if (itemObj.label && searchBox__isStringMatch(itemObj.label, query)) return true;
  253. if (itemObj.name && searchBox__isStringMatch(itemObj.name, query)) return true;
  254. if (itemObj.opis && searchBox__isStringMatch(itemObj.opis, query)) return true;
  255. if (itemObj.namespace && searchBox__isStringMatch(itemObj.namespace, query)) return true;
  256. // if (itemObj.desc && searchBox__isStringMatch(itemObj.desc, query)) return true;
  257. // if (itemObj.short_label && searchBox__isStringMatch(itemObj.short_label, query)) return true;
  258. // if (itemObj.id && searchBox__isStringMatch(itemObj.id, query)) return true;
  259. return false;
  260. }
  261. function searchBox__isMenuItemMatch(node, query) {
  262. DBG && console.log("DBG:Main menu:searchBox__isMenuItemMatch", { query: query, label: jQuery(node).children('a').text(), node: node })
  263. if (node.hasAttribute('data-id')) {
  264. var id = parseInt(node.getAttribute('data-id'));
  265. var itemObj = menuStore__getObjectById(id);
  266. return searchBox__isMenuObjectMatch(itemObj, query);
  267. }
  268. if (node.hasChildNodes()) {
  269. {
  270. var groupItemLabel = jQuery(node).children('a').text()
  271. if (searchBox__isStringMatch(groupItemLabel, query)) return true;
  272. }
  273. // DBG && console.log("DBG:Main menu:searchBox__isMenuItemMatch: loop start...", { query: query, label: jQuery(node).children('a').text(), node: node })
  274. for (var i = 0, l = node.childNodes.length; i < l; i++) {
  275. if ("UL" === node.childNodes[i].tagName) {
  276. // DBG && console.log("DBG:Main menu:searchBox__isMenuItemMatch: loop UL ", { query: query, label: jQuery(node).children('a').text(), node: node })
  277. for (var j = 0, l = node.childNodes[i].childNodes.length; j < l; j++) {
  278. if ("LI" === node.childNodes[i].childNodes[j].tagName) {
  279. // DBG && console.log("DBG:Main menu:searchBox__isMenuItemMatch: loop UL > LI ", { query: query, label: jQuery(node).children('a').text(), node: node })
  280. if (searchBox__isMenuItemMatch(node.childNodes[i].childNodes[j], query)) {
  281. return true;
  282. }
  283. }
  284. }
  285. break;
  286. }
  287. }
  288. }
  289. return false;
  290. }
  291. function makeMainMenuFilterCallback(jqDropdownMenu, jqDropdownTrigger) {
  292. return function (query) {
  293. DBG && console.log("DBG:Main menu:makeMainMenuFilterCallback", { query: query, jqDropdownMenu, jqDropdownTrigger })
  294. jqDropdownMenu.children('li').each(function (idx, node) {
  295. node.style.display = "list-item";
  296. })
  297. if (!query || query.length < 3) return;
  298. jqDropdownMenu.children('li').each(function (idx, node) {
  299. // if (node.style.display === "none") node.style.display = "";
  300. var id = (node.hasAttribute('data-id')) ? parseInt(node.getAttribute('data-id')) : null;
  301. var itemObj = (id) ? menuStore__getObjectById(id) : null;
  302. var isMatch = searchBox__isMenuItemMatch(node, query)
  303. DBG && console.log("DBG:Main menu:makeMainMenuFilterCallback:loop", { isMatch: isMatch, id: id, itemObj: itemObj, display: node.style.display, node: node })
  304. node.style.display = isMatch ? "list-item" : "none";
  305. })
  306. }
  307. }
  308. var _config_delay_value = 450;
  309. var _config_delay_timeout = null;
  310. function searchBox_delayFilter(callback, value) {
  311. // DBG && console.log('DBG:searchBox:delayFilter', { value });
  312. if (_config_delay_timeout) clearTimeout(_config_delay_timeout)
  313. _config_delay_timeout = setTimeout(function () {
  314. DBG && console.log("DBG:Main menu:delayFilter", { value: value })
  315. callback(value)
  316. }, _config_delay_value)
  317. }
  318. global.initP5MainMenuDropdown = initP5MainMenuDropdown