menu_top.js 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. /**
  2. * Copyright (c) UNA, Inc - https://una.io
  3. * MIT License - https://opensource.org/licenses/MIT
  4. *
  5. * @defgroup UnaStudio UNA Studio
  6. * @{
  7. */
  8. function BxDolStudioMenuTop(oOptions) {
  9. this.sActionsUrl = oOptions.sActionUrl;
  10. this.sObjName = oOptions.sObjName == undefined ? 'oBxDolStudioMenuTop' : oOptions.sObjName;
  11. this.sAnimationEffect = oOptions.sAnimationEffect == undefined ? 'slide' : oOptions.sAnimationEffect;
  12. this.iAnimationSpeed = oOptions.iAnimationSpeed == undefined ? 'slow' : oOptions.iAnimationSpeed;
  13. bx_set_color_scheme_html();
  14. var $this = this;
  15. $(document).ready(function() {
  16. $this.markTheme();
  17. $this.searchInit();
  18. });
  19. //--- Theme radios: arrows move between the options and apply them, as in a native radio group.
  20. $(document).on('keydown', '.bx-theme-toggle [role="radio"]', function(oEvent) {
  21. var aKeys = {ArrowLeft: -1, ArrowUp: -1, ArrowRight: 1, ArrowDown: 1};
  22. if(!(oEvent.key in aKeys))
  23. return true;
  24. var oOptions = $(this).closest('.bx-theme-toggle').find('[role="radio"]');
  25. oOptions.eq((oOptions.index(this) + aKeys[oEvent.key] + oOptions.length) % oOptions.length).trigger('focus').trigger('click');
  26. return false;
  27. });
  28. }
  29. /**
  30. * Launcher search sizing: the field needs at least 12rem next to the launcher icon; when the left
  31. * header section can't give it that, the item collapses to a trigger button (.bx-mt-compact).
  32. */
  33. BxDolStudioMenuTop.prototype.searchInit = function() {
  34. var $this = this;
  35. var oLeft = document.querySelector('.bx-std-menu-top-left');
  36. var oItem = oLeft ? oLeft.querySelector('li.bx-menu-tab-search') : null;
  37. if(!oItem || typeof ResizeObserver === 'undefined')
  38. return;
  39. var iMinField = 192; // min-w-48
  40. this.fSearchMeasure = function() {
  41. if(oItem.classList.contains('bx-mt-active'))
  42. return; // the open field owns the header, don't re-measure until it closes
  43. var iSiblings = 0;
  44. $(oItem).siblings(':visible').each(function() {
  45. iSiblings += $(this).outerWidth(true);
  46. });
  47. var oStyle = getComputedStyle(oLeft);
  48. var iAvailable = oLeft.clientWidth - parseFloat(oStyle.paddingLeft) - parseFloat(oStyle.paddingRight) - iSiblings;
  49. oItem.classList.toggle('bx-mt-compact', iAvailable < iMinField);
  50. };
  51. new ResizeObserver(this.fSearchMeasure).observe(oLeft);
  52. this.fSearchMeasure();
  53. };
  54. BxDolStudioMenuTop.prototype.searchClose = function(oItem) {
  55. oItem = $(oItem).closest('li.bx-menu-tab-search');
  56. if(!oItem.hasClass('bx-mt-active'))
  57. return;
  58. oItem.removeClass('bx-mt-active');
  59. oItem.find('.bx-std-search-trigger').attr('aria-expanded', 'false');
  60. if(typeof this.fSearchMeasure == 'function')
  61. this.fSearchMeasure();
  62. };
  63. BxDolStudioMenuTop.prototype.searchKey = function(oEvent) {
  64. var oInput = $(oEvent.target);
  65. if(oEvent.key == 'Enter') {
  66. var oPick = $('.bx-std-widgets .bx-std-widget-icon-pick .bx-std-widget-link:first');
  67. if(oInput.val() != '' && oPick.length)
  68. oPick[0].click(); // the tile link carries the app URL or its onclick handler
  69. return false;
  70. }
  71. if(oEvent.key != 'Escape')
  72. return true;
  73. if(oInput.val() != '') {
  74. oInput.val('');
  75. this.searchWidget(oEvent);
  76. return false;
  77. }
  78. var oItem = oInput.closest('li.bx-menu-tab-search');
  79. if(oItem.hasClass('bx-mt-compact')) {
  80. this.searchClose(oItem);
  81. oItem.find('.bx-std-search-trigger').trigger('focus');
  82. }
  83. else
  84. oInput.trigger('blur');
  85. return false;
  86. };
  87. BxDolStudioMenuTop.prototype.searchBlur = function(oInput) {
  88. var oItem = $(oInput).closest('li.bx-menu-tab-search');
  89. if(oItem.hasClass('bx-mt-compact') && $(oInput).val() == '')
  90. this.searchClose(oItem);
  91. };
  92. BxDolStudioMenuTop.prototype.setTheme = function(oButton, iCode) {
  93. bx_set_color_scheme(iCode);
  94. this.markTheme();
  95. };
  96. /**
  97. * Reflect the stored theme ('auto', 'sun' or 'dark') on the segmented control in the account menu.
  98. */
  99. BxDolStudioMenuTop.prototype.markTheme = function() {
  100. var sTheme = bx_get_color_scheme();
  101. $('.bx-theme-option').each(function() {
  102. var bChecked = $(this).data('bx-theme') == sTheme;
  103. $(this).attr('aria-checked', bChecked ? 'true' : 'false').attr('tabindex', bChecked ? '0' : '-1');
  104. });
  105. };
  106. BxDolStudioMenuTop.prototype.clickEdit = function(oItem) {
  107. $('.bx-popup-applied:visible').dolPopupHide();
  108. if(oBxDolStudioLauncher.bJitterMode)
  109. oBxDolStudioLauncher.disableJitter();
  110. else
  111. oBxDolStudioLauncher.enableJitter();
  112. };
  113. BxDolStudioMenuTop.prototype.clickLogout = function(oItem) {
  114. $(oItem).parent().toggleClass('bx-menu-tab-active');
  115. };
  116. BxDolStudioMenuTop.prototype.searchToggle = function(oLink) {
  117. var oItem = $(oLink).closest('li.bx-menu-tab-search');
  118. oItem.toggleClass('bx-mt-active');
  119. var bActive = oItem.hasClass('bx-mt-active');
  120. $(oLink).attr('aria-expanded', bActive ? 'true' : 'false');
  121. if(bActive)
  122. oItem.find('input[name="search"]').trigger('focus');
  123. return false;
  124. };
  125. BxDolStudioMenuTop.prototype.searchWidget = function(oEvent) {
  126. this.searchFilter($(oEvent.target));
  127. };
  128. /**
  129. * Show the apps whose name starts with the field's text (every app for an empty field), pick the first one for Enter
  130. * and report the count; one pass per pause in typing.
  131. */
  132. BxDolStudioMenuTop.prototype.searchFilter = function(oInput) {
  133. var $this = this;
  134. // the clear button shows only while there is something to clear
  135. oInput.siblings('.bx-std-search-clear').prop('hidden', !oInput.val().length);
  136. clearTimeout(this.iSearchTimer);
  137. this.iSearchTimer = setTimeout(function () {
  138. var sSearch = oInput.val().toLowerCase();
  139. var oWidgets = $('.bx-std-widgets > .bx-std-widget');
  140. oWidgets.each(function() {
  141. $(this).toggle(!sSearch.length || String($(this).data('name')).toLowerCase().indexOf(sSearch) === 0);
  142. });
  143. var oVisible = oWidgets.filter(':visible');
  144. $this.searchPick(sSearch.length ? oVisible.first() : null);
  145. if(typeof oBxDolStudioLauncher !== 'undefined')
  146. oBxDolStudioLauncher.searchResult(sSearch, oVisible.length);
  147. }, 100);
  148. };
  149. /**
  150. * The field's clear button: empty the field, show every app again and hand focus back to the field.
  151. */
  152. BxDolStudioMenuTop.prototype.searchClear = function(oButton) {
  153. var oInput = $(oButton).siblings('input');
  154. if(!oInput.length)
  155. return false;
  156. oInput.val('');
  157. this.searchFilter(oInput);
  158. oInput.trigger('focus');
  159. return false;
  160. };
  161. /**
  162. * Highlight one tile as the choice Enter will open (the first match while filtering); pass null to clear.
  163. */
  164. BxDolStudioMenuTop.prototype.searchPick = function(oWidget) {
  165. var sClass = 'bx-std-widget-icon-pick';
  166. $('.bx-std-widgets .' + sClass).removeClass(sClass);
  167. if(oWidget && oWidget.length)
  168. oWidget.find('.bx-std-widget-icon').addClass(sClass);
  169. };
  170. /** @} */