nodebb-theme-harmony 1.2.96 → 1.2.97

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (142) hide show
  1. package/.eslintrc +3 -3
  2. package/README.md +22 -22
  3. package/lib/controllers.js +29 -29
  4. package/library.js +190 -190
  5. package/package.json +48 -48
  6. package/plugin.json +25 -25
  7. package/public/.eslintrc +3 -3
  8. package/public/admin.js +15 -15
  9. package/public/harmony.js +287 -287
  10. package/public/settings.js +31 -31
  11. package/renovate.json +6 -6
  12. package/scss/account.scss +27 -27
  13. package/scss/category.scss +3 -3
  14. package/scss/chats.scss +11 -11
  15. package/scss/common.scss +122 -122
  16. package/scss/fonts.scss +19 -19
  17. package/scss/groups.scss +22 -22
  18. package/scss/harmony.scss +24 -24
  19. package/scss/header.scss +15 -15
  20. package/scss/mixins.scss +176 -176
  21. package/scss/modals.scss +6 -6
  22. package/scss/modules/breadcrumbs.scss +15 -15
  23. package/scss/modules/cover.scss +102 -102
  24. package/scss/modules/filters.scss +7 -7
  25. package/scss/modules/nprogress.scss +80 -80
  26. package/scss/modules/paginator.scss +23 -23
  27. package/scss/modules/tags.scss +5 -5
  28. package/scss/modules/topic-navigator.scss +52 -52
  29. package/scss/modules/topics-list.scss +40 -40
  30. package/scss/modules/user-menu.scss +10 -10
  31. package/scss/overrides.scss +65 -65
  32. package/scss/sidebar.scss +188 -188
  33. package/scss/skins.scss +58 -58
  34. package/scss/status.scss +24 -24
  35. package/scss/topic.scss +130 -130
  36. package/templates/account/blocks.tpl +51 -51
  37. package/templates/account/categories.tpl +63 -63
  38. package/templates/account/consent.tpl +73 -73
  39. package/templates/account/edit/password.tpl +34 -34
  40. package/templates/account/edit/username.tpl +29 -29
  41. package/templates/account/edit.tpl +137 -137
  42. package/templates/account/followers.tpl +14 -14
  43. package/templates/account/following.tpl +15 -15
  44. package/templates/account/groups.tpl +15 -15
  45. package/templates/account/info.tpl +270 -270
  46. package/templates/account/posts.tpl +35 -35
  47. package/templates/account/profile.tpl +92 -92
  48. package/templates/account/sessions.tpl +8 -8
  49. package/templates/account/settings.tpl +236 -236
  50. package/templates/account/tags.tpl +12 -12
  51. package/templates/account/theme.tpl +63 -63
  52. package/templates/account/topics.tpl +44 -44
  53. package/templates/account/uploads.tpl +37 -37
  54. package/templates/admin/plugins/harmony.tpl +57 -57
  55. package/templates/categories.tpl +29 -29
  56. package/templates/category.tpl +72 -72
  57. package/templates/footer.tpl +17 -17
  58. package/templates/groups/details.tpl +86 -86
  59. package/templates/groups/list.tpl +58 -58
  60. package/templates/groups/members.tpl +9 -9
  61. package/templates/header.tpl +45 -45
  62. package/templates/notifications.tpl +32 -32
  63. package/templates/partials/account/admin-menu.tpl +36 -36
  64. package/templates/partials/account/category-item.tpl +22 -22
  65. package/templates/partials/account/footer.tpl +2 -2
  66. package/templates/partials/account/header.tpl +98 -98
  67. package/templates/partials/account/session-list.tpl +18 -18
  68. package/templates/partials/account/sidebar-left.tpl +102 -102
  69. package/templates/partials/breadcrumbs-json-ld.tpl +15 -15
  70. package/templates/partials/breadcrumbs.tpl +12 -12
  71. package/templates/partials/buttons/newTopic.tpl +22 -22
  72. package/templates/partials/categories/item.tpl +56 -56
  73. package/templates/partials/categories/lastpost.tpl +24 -24
  74. package/templates/partials/categories/link.tpl +4 -4
  75. package/templates/partials/category/subcategory.tpl +18 -18
  76. package/templates/partials/category/tags.tpl +3 -3
  77. package/templates/partials/cookie-consent.tpl +6 -6
  78. package/templates/partials/groups/admin.tpl +95 -95
  79. package/templates/partials/groups/invited.tpl +32 -32
  80. package/templates/partials/groups/list.tpl +15 -15
  81. package/templates/partials/groups/memberlist.tpl +46 -46
  82. package/templates/partials/groups/pending.tpl +29 -29
  83. package/templates/partials/groups/sidebar-left.tpl +27 -27
  84. package/templates/partials/header/brand.tpl +27 -27
  85. package/templates/partials/mobile-footer.tpl +95 -95
  86. package/templates/partials/notifications_list.tpl +44 -44
  87. package/templates/partials/paginator.tpl +46 -46
  88. package/templates/partials/post_bar.tpl +27 -27
  89. package/templates/partials/posts_list.tpl +7 -7
  90. package/templates/partials/posts_list_item.tpl +19 -19
  91. package/templates/partials/quick-search-results.tpl +46 -46
  92. package/templates/partials/search-filters.tpl +183 -183
  93. package/templates/partials/search-results.tpl +54 -54
  94. package/templates/partials/sidebar/chats.tpl +45 -45
  95. package/templates/partials/sidebar/drafts.tpl +63 -63
  96. package/templates/partials/sidebar/logged-in-menu.tpl +22 -22
  97. package/templates/partials/sidebar/logged-out-menu.tpl +44 -44
  98. package/templates/partials/sidebar/notifications.tpl +49 -49
  99. package/templates/partials/sidebar/search-mobile.tpl +28 -28
  100. package/templates/partials/sidebar/search.tpl +30 -30
  101. package/templates/partials/sidebar/user-menu.tpl +103 -103
  102. package/templates/partials/sidebar-left.tpl +39 -39
  103. package/templates/partials/sidebar-right.tpl +16 -16
  104. package/templates/partials/skin-switcher.tpl +50 -50
  105. package/templates/partials/tags_list.tpl +7 -7
  106. package/templates/partials/toast.tpl +19 -19
  107. package/templates/partials/topic/event.tpl +12 -12
  108. package/templates/partials/topic/navigation-post.tpl +9 -9
  109. package/templates/partials/topic/navigator-mobile.tpl +61 -61
  110. package/templates/partials/topic/navigator.tpl +26 -26
  111. package/templates/partials/topic/necro-post.tpl +5 -5
  112. package/templates/partials/topic/post-menu-list.tpl +142 -142
  113. package/templates/partials/topic/post-menu.tpl +4 -4
  114. package/templates/partials/topic/post-placeholder.tpl +14 -14
  115. package/templates/partials/topic/post.tpl +128 -128
  116. package/templates/partials/topic/quickreply.tpl +28 -28
  117. package/templates/partials/topic/reply-button.tpl +26 -26
  118. package/templates/partials/topic/selection-tooltip.tpl +2 -2
  119. package/templates/partials/topic/sort.tpl +27 -27
  120. package/templates/partials/topic/stats.tpl +14 -14
  121. package/templates/partials/topic/thumbs.tpl +4 -4
  122. package/templates/partials/topic/tools.tpl +8 -8
  123. package/templates/partials/topic/topic-menu-list.tpl +73 -73
  124. package/templates/partials/topic/watch.tpl +59 -59
  125. package/templates/partials/topic-filters.tpl +15 -15
  126. package/templates/partials/topic-list-bar.tpl +54 -54
  127. package/templates/partials/topic-terms.tpl +15 -15
  128. package/templates/partials/topics_list.tpl +131 -131
  129. package/templates/partials/users/item.tpl +39 -39
  130. package/templates/partials/users_list.tpl +4 -4
  131. package/templates/partials/users_list_menu.tpl +14 -14
  132. package/templates/popular.tpl +34 -34
  133. package/templates/post-queue.tpl +211 -211
  134. package/templates/recent.tpl +35 -35
  135. package/templates/search.tpl +46 -46
  136. package/templates/tag.tpl +34 -34
  137. package/templates/tags.tpl +49 -49
  138. package/templates/top.tpl +34 -34
  139. package/templates/topic.tpl +123 -123
  140. package/templates/unread.tpl +31 -31
  141. package/templates/users.tpl +39 -39
  142. package/theme.json +6 -6
package/public/admin.js CHANGED
@@ -1,15 +1,15 @@
1
- 'use strict';
2
-
3
- define('admin/plugins/harmony', ['settings'], function (Settings) {
4
- var ACP = {};
5
-
6
- ACP.init = function () {
7
- Settings.load('harmony', $('.harmony-settings'));
8
-
9
- $('#save').on('click', function () {
10
- Settings.save('harmony', $('.harmony-settings'));
11
- });
12
- };
13
-
14
- return ACP;
15
- });
1
+ 'use strict';
2
+
3
+ define('admin/plugins/harmony', ['settings'], function (Settings) {
4
+ var ACP = {};
5
+
6
+ ACP.init = function () {
7
+ Settings.load('harmony', $('.harmony-settings'));
8
+
9
+ $('#save').on('click', function () {
10
+ Settings.save('harmony', $('.harmony-settings'));
11
+ });
12
+ };
13
+
14
+ return ACP;
15
+ });
package/public/harmony.js CHANGED
@@ -1,287 +1,287 @@
1
- 'use strict';
2
-
3
- $(document).ready(function () {
4
- setupSkinSwitcher();
5
- setupNProgress();
6
- setupMobileMenu();
7
- setupSearch();
8
- setupDrafts();
9
- handleMobileNavigator();
10
- setupNavTooltips();
11
- fixPlaceholders();
12
- fixSidebarOverflow();
13
-
14
- function setupSkinSwitcher() {
15
- $('[component="skinSwitcher"]').on('click', '.dropdown-item', function () {
16
- const skin = $(this).attr('data-value');
17
- $('[component="skinSwitcher"] .dropdown-item .fa-check').addClass('invisible');
18
- $(this).find('.fa-check').removeClass('invisible');
19
- require(['forum/account/settings', 'hooks'], function (accountSettings, hooks) {
20
- hooks.one('action:skin.change', function () {
21
- $('[component="skinSwitcher"] [component="skinSwitcher/icon"]').removeClass('fa-fade');
22
- });
23
- $('[component="skinSwitcher"] [component="skinSwitcher/icon"]').addClass('fa-fade');
24
- accountSettings.changeSkin(skin);
25
- });
26
- });
27
- }
28
-
29
- require(['hooks'], function (hooks) {
30
- $(window).on('action:composer.resize action:sidebar.toggle', function () {
31
- const isRtl = $('html').attr('data-dir') === 'rtl';
32
- const css = {
33
- width: $('#panel').width(),
34
- };
35
- const sidebarEl = $('.sidebar-left');
36
- css[isRtl ? 'right' : 'left'] = sidebarEl.is(':visible') ? sidebarEl.outerWidth(true) : 0;
37
- $('[component="composer"]').css(css);
38
- });
39
-
40
- hooks.on('filter:chat.openChat', function (hookData) {
41
- // disables chat modals & goes straight to chat page based on user setting
42
- hookData.modal = config.theme.chatModals && !utils.isMobile();
43
- return hookData;
44
- });
45
- });
46
-
47
- function setupMobileMenu() {
48
- require(['hooks', 'api', 'navigator'], function (hooks, api, navigator) {
49
- $('[component="sidebar/toggle"]').on('click', async function () {
50
- const sidebarEl = $('.sidebar');
51
- sidebarEl.toggleClass('open');
52
- if (app.user.uid) {
53
- await api.put(`/users/${app.user.uid}/settings`, {
54
- settings: {
55
- openSidebars: sidebarEl.hasClass('open') ? 'on' : 'off',
56
- },
57
- });
58
- }
59
- $(window).trigger('action:sidebar.toggle');
60
- if (ajaxify.data.template.topic) {
61
- hooks.fire('action:navigator.update', { newIndex: navigator.getIndex() });
62
- }
63
- });
64
-
65
- const bottomBar = $('[component="bottombar"]');
66
- const $body = $('body');
67
- const $window = $(window);
68
- $body.on('shown.bs.dropdown hidden.bs.dropdown', '.sticky-tools', function () {
69
- bottomBar.toggleClass('hidden', $(this).find('.dropdown-menu.show').length);
70
- });
71
- function isSearchVisible() {
72
- return !!$('[component="bottombar"] [component="sidebar/search"] .search-dropdown.show').length;
73
- }
74
-
75
- let lastScrollTop = $window.scrollTop();
76
- let newPostsLoaded = false;
77
-
78
- function onWindowScroll() {
79
- const st = $window.scrollTop();
80
- if (newPostsLoaded) {
81
- newPostsLoaded = false;
82
- lastScrollTop = st;
83
- return;
84
- }
85
- if (st !== lastScrollTop && !navigator.scrollActive && !isSearchVisible()) {
86
- const diff = Math.abs(st - lastScrollTop);
87
- const scrolledDown = st > lastScrollTop;
88
- const scrolledUp = st < lastScrollTop;
89
- if (diff > 10) {
90
- bottomBar.css({
91
- bottom: !scrolledUp && scrolledDown ?
92
- -bottomBar.find('.bottombar-nav').outerHeight(true) :
93
- 0,
94
- });
95
- }
96
- }
97
- lastScrollTop = st;
98
- }
99
-
100
- const delayedScroll = utils.throttle(onWindowScroll, 250);
101
- function enableAutohide() {
102
- $window.off('scroll', delayedScroll);
103
- if (config.theme.autohideBottombar) {
104
- lastScrollTop = $window.scrollTop();
105
- $window.on('scroll', delayedScroll);
106
- }
107
- }
108
-
109
- hooks.on('action:posts.loading', function () {
110
- $window.off('scroll', delayedScroll);
111
- });
112
- hooks.on('action:posts.loaded', function () {
113
- newPostsLoaded = true;
114
- setTimeout(enableAutohide, 250);
115
- });
116
- hooks.on('action:ajaxify.end', function () {
117
- $window.off('scroll', delayedScroll);
118
- if (config.theme.autohideBottombar) {
119
- bottomBar.css({ bottom: 0 });
120
- setTimeout(enableAutohide, 250);
121
- }
122
- });
123
- });
124
- }
125
-
126
- function setupSearch() {
127
- $('[component="sidebar/search"]').on('shown.bs.dropdown', function () {
128
- $(this).find('[component="search/fields"] input[name="query"]').trigger('focus');
129
- });
130
- }
131
-
132
- function setupDrafts() {
133
- require(['composer/drafts', 'bootbox'], function (drafts, bootbox) {
134
- const draftsEl = $('[component="sidebar/drafts"]');
135
-
136
- function updateBadgeCount() {
137
- const count = drafts.getAvailableCount();
138
- if (count > 0) {
139
- draftsEl.removeClass('hidden');
140
- }
141
- $('[component="drafts/count"]').toggleClass('hidden', count <= 0).text(count);
142
- }
143
-
144
- async function renderDraftList() {
145
- const draftListEl = $('[component="drafts/list"]');
146
- const draftItems = drafts.listAvailable();
147
- if (!draftItems.length) {
148
- draftListEl.find('.no-drafts').removeClass('hidden');
149
- draftListEl.find('.placeholder-wave').addClass('hidden');
150
- draftListEl.find('.draft-item-container').html('');
151
- return;
152
- }
153
- draftItems.reverse().forEach((draft) => {
154
- if (draft) {
155
- if (draft.title) {
156
- draft.title = utils.escapeHTML(String(draft.title));
157
- }
158
- draft.text = utils.escapeHTML(
159
- draft.text
160
- ).replace(/(?:\r\n|\r|\n)/g, '<br>');
161
- }
162
- });
163
-
164
- const html = await app.parseAndTranslate('partials/sidebar/drafts', 'drafts', { drafts: draftItems });
165
- draftListEl.find('.no-drafts').addClass('hidden');
166
- draftListEl.find('.placeholder-wave').addClass('hidden');
167
- draftListEl.find('.draft-item-container').html(html).find('.timeago').timeago();
168
- }
169
-
170
-
171
- draftsEl.on('shown.bs.dropdown', renderDraftList);
172
-
173
- draftsEl.on('click', '[component="drafts/open"]', function () {
174
- drafts.open($(this).attr('data-save-id'));
175
- });
176
-
177
- draftsEl.on('click', '[component="drafts/delete"]', function () {
178
- const save_id = $(this).attr('data-save-id');
179
- bootbox.confirm('[[modules:composer.discard-draft-confirm]]', function (ok) {
180
- if (ok) {
181
- drafts.removeDraft(save_id);
182
- renderDraftList();
183
- }
184
- });
185
- return false;
186
- });
187
-
188
- $(window).on('action:composer.drafts.save', updateBadgeCount);
189
- $(window).on('action:composer.drafts.remove', updateBadgeCount);
190
- updateBadgeCount();
191
- });
192
- }
193
-
194
- function setupNProgress() {
195
- require(['nprogress'], function (NProgress) {
196
- window.nprogress = NProgress;
197
- if (NProgress) {
198
- $(window).on('action:ajaxify.start', function () {
199
- NProgress.set(0.7);
200
- });
201
-
202
- $(window).on('action:ajaxify.end', function () {
203
- NProgress.done(true);
204
- });
205
- }
206
- });
207
- }
208
-
209
- function handleMobileNavigator() {
210
- const paginationBlockEl = $('.pagination-block');
211
- require(['hooks'], function (hooks) {
212
- hooks.on('action:ajaxify.end', function () {
213
- paginationBlockEl.find('.dropdown-menu.show').removeClass('show');
214
- });
215
- hooks.on('filter:navigator.scroll', function (hookData) {
216
- paginationBlockEl.find('.dropdown-menu.show').removeClass('show');
217
- return hookData;
218
- });
219
- });
220
- }
221
-
222
- function setupNavTooltips() {
223
- // remove title from user icon in sidebar to prevent double tooltip
224
- $('.sidebar [component="header/avatar"] .avatar').removeAttr('title');
225
- const tooltipEls = $('.sidebar [title]');
226
- const lefttooltipEls = $('.sidebar-left [title]');
227
- const rightooltipEls = $('.sidebar-right [title]');
228
- const isRtl = $('html').attr('data-dir') === 'rtl';
229
- lefttooltipEls.tooltip({
230
- trigger: 'manual',
231
- animation: false,
232
- placement: isRtl ? 'left' : 'right',
233
- });
234
- rightooltipEls.tooltip({
235
- trigger: 'manual',
236
- animation: false,
237
- placement: isRtl ? 'right' : 'left',
238
- });
239
-
240
- tooltipEls.on('mouseenter', function (ev) {
241
- const target = $(ev.target);
242
- const isDropdown = target.hasClass('dropdown-menu') || !!target.parents('.dropdown-menu').length;
243
- if (!$('.sidebar').hasClass('open') && !isDropdown) {
244
- $(this).tooltip('show');
245
- }
246
- });
247
- tooltipEls.on('click mouseleave', function () {
248
- $(this).tooltip('hide');
249
- });
250
- }
251
-
252
- function fixPlaceholders() {
253
- if (!config.loggedIn) {
254
- return;
255
- }
256
- ['notifications', 'chat'].forEach((type) => {
257
- const countEl = $(`nav.sidebar [component="${type}/count"]`).first();
258
- if (!countEl.length) {
259
- return;
260
- }
261
- const count = parseInt(countEl.text(), 10);
262
- if (count > 1) {
263
- const listEls = $(`.dropdown-menu [component="${type}/list"]`);
264
- listEls.each((index, el) => {
265
- const placeholder = $(el).children().first();
266
- for (let x = 0; x < count - 1; x++) {
267
- const cloneEl = placeholder.clone(true);
268
- cloneEl.insertAfter(placeholder);
269
- }
270
- });
271
- }
272
- });
273
- }
274
-
275
- function fixSidebarOverflow() {
276
- // overflow-y-auto needs to be removed on main-nav when dropdowns are opened
277
- const mainNavEl = $('#main-nav');
278
- function toggleOverflow() {
279
- mainNavEl.toggleClass(
280
- 'overflow-y-auto',
281
- !mainNavEl.find('.dropdown-menu.show').length
282
- );
283
- }
284
- mainNavEl.on('shown.bs.dropdown', toggleOverflow)
285
- .on('hidden.bs.dropdown', toggleOverflow);
286
- }
287
- });
1
+ 'use strict';
2
+
3
+ $(document).ready(function () {
4
+ setupSkinSwitcher();
5
+ setupNProgress();
6
+ setupMobileMenu();
7
+ setupSearch();
8
+ setupDrafts();
9
+ handleMobileNavigator();
10
+ setupNavTooltips();
11
+ fixPlaceholders();
12
+ fixSidebarOverflow();
13
+
14
+ function setupSkinSwitcher() {
15
+ $('[component="skinSwitcher"]').on('click', '.dropdown-item', function () {
16
+ const skin = $(this).attr('data-value');
17
+ $('[component="skinSwitcher"] .dropdown-item .fa-check').addClass('invisible');
18
+ $(this).find('.fa-check').removeClass('invisible');
19
+ require(['forum/account/settings', 'hooks'], function (accountSettings, hooks) {
20
+ hooks.one('action:skin.change', function () {
21
+ $('[component="skinSwitcher"] [component="skinSwitcher/icon"]').removeClass('fa-fade');
22
+ });
23
+ $('[component="skinSwitcher"] [component="skinSwitcher/icon"]').addClass('fa-fade');
24
+ accountSettings.changeSkin(skin);
25
+ });
26
+ });
27
+ }
28
+
29
+ require(['hooks'], function (hooks) {
30
+ $(window).on('action:composer.resize action:sidebar.toggle', function () {
31
+ const isRtl = $('html').attr('data-dir') === 'rtl';
32
+ const css = {
33
+ width: $('#panel').width(),
34
+ };
35
+ const sidebarEl = $('.sidebar-left');
36
+ css[isRtl ? 'right' : 'left'] = sidebarEl.is(':visible') ? sidebarEl.outerWidth(true) : 0;
37
+ $('[component="composer"]').css(css);
38
+ });
39
+
40
+ hooks.on('filter:chat.openChat', function (hookData) {
41
+ // disables chat modals & goes straight to chat page based on user setting
42
+ hookData.modal = config.theme.chatModals && !utils.isMobile();
43
+ return hookData;
44
+ });
45
+ });
46
+
47
+ function setupMobileMenu() {
48
+ require(['hooks', 'api', 'navigator'], function (hooks, api, navigator) {
49
+ $('[component="sidebar/toggle"]').on('click', async function () {
50
+ const sidebarEl = $('.sidebar');
51
+ sidebarEl.toggleClass('open');
52
+ if (app.user.uid) {
53
+ await api.put(`/users/${app.user.uid}/settings`, {
54
+ settings: {
55
+ openSidebars: sidebarEl.hasClass('open') ? 'on' : 'off',
56
+ },
57
+ });
58
+ }
59
+ $(window).trigger('action:sidebar.toggle');
60
+ if (ajaxify.data.template.topic) {
61
+ hooks.fire('action:navigator.update', { newIndex: navigator.getIndex() });
62
+ }
63
+ });
64
+
65
+ const bottomBar = $('[component="bottombar"]');
66
+ const $body = $('body');
67
+ const $window = $(window);
68
+ $body.on('shown.bs.dropdown hidden.bs.dropdown', '.sticky-tools', function () {
69
+ bottomBar.toggleClass('hidden', $(this).find('.dropdown-menu.show').length);
70
+ });
71
+ function isSearchVisible() {
72
+ return !!$('[component="bottombar"] [component="sidebar/search"] .search-dropdown.show').length;
73
+ }
74
+
75
+ let lastScrollTop = $window.scrollTop();
76
+ let newPostsLoaded = false;
77
+
78
+ function onWindowScroll() {
79
+ const st = $window.scrollTop();
80
+ if (newPostsLoaded) {
81
+ newPostsLoaded = false;
82
+ lastScrollTop = st;
83
+ return;
84
+ }
85
+ if (st !== lastScrollTop && !navigator.scrollActive && !isSearchVisible()) {
86
+ const diff = Math.abs(st - lastScrollTop);
87
+ const scrolledDown = st > lastScrollTop;
88
+ const scrolledUp = st < lastScrollTop;
89
+ if (diff > 10) {
90
+ bottomBar.css({
91
+ bottom: !scrolledUp && scrolledDown ?
92
+ -bottomBar.find('.bottombar-nav').outerHeight(true) :
93
+ 0,
94
+ });
95
+ }
96
+ }
97
+ lastScrollTop = st;
98
+ }
99
+
100
+ const delayedScroll = utils.throttle(onWindowScroll, 250);
101
+ function enableAutohide() {
102
+ $window.off('scroll', delayedScroll);
103
+ if (config.theme.autohideBottombar) {
104
+ lastScrollTop = $window.scrollTop();
105
+ $window.on('scroll', delayedScroll);
106
+ }
107
+ }
108
+
109
+ hooks.on('action:posts.loading', function () {
110
+ $window.off('scroll', delayedScroll);
111
+ });
112
+ hooks.on('action:posts.loaded', function () {
113
+ newPostsLoaded = true;
114
+ setTimeout(enableAutohide, 250);
115
+ });
116
+ hooks.on('action:ajaxify.end', function () {
117
+ $window.off('scroll', delayedScroll);
118
+ if (config.theme.autohideBottombar) {
119
+ bottomBar.css({ bottom: 0 });
120
+ setTimeout(enableAutohide, 250);
121
+ }
122
+ });
123
+ });
124
+ }
125
+
126
+ function setupSearch() {
127
+ $('[component="sidebar/search"]').on('shown.bs.dropdown', function () {
128
+ $(this).find('[component="search/fields"] input[name="query"]').trigger('focus');
129
+ });
130
+ }
131
+
132
+ function setupDrafts() {
133
+ require(['composer/drafts', 'bootbox'], function (drafts, bootbox) {
134
+ const draftsEl = $('[component="sidebar/drafts"]');
135
+
136
+ function updateBadgeCount() {
137
+ const count = drafts.getAvailableCount();
138
+ if (count > 0) {
139
+ draftsEl.removeClass('hidden');
140
+ }
141
+ $('[component="drafts/count"]').toggleClass('hidden', count <= 0).text(count);
142
+ }
143
+
144
+ async function renderDraftList() {
145
+ const draftListEl = $('[component="drafts/list"]');
146
+ const draftItems = drafts.listAvailable();
147
+ if (!draftItems.length) {
148
+ draftListEl.find('.no-drafts').removeClass('hidden');
149
+ draftListEl.find('.placeholder-wave').addClass('hidden');
150
+ draftListEl.find('.draft-item-container').html('');
151
+ return;
152
+ }
153
+ draftItems.reverse().forEach((draft) => {
154
+ if (draft) {
155
+ if (draft.title) {
156
+ draft.title = utils.escapeHTML(String(draft.title));
157
+ }
158
+ draft.text = utils.escapeHTML(
159
+ draft.text
160
+ ).replace(/(?:\r\n|\r|\n)/g, '<br>');
161
+ }
162
+ });
163
+
164
+ const html = await app.parseAndTranslate('partials/sidebar/drafts', 'drafts', { drafts: draftItems });
165
+ draftListEl.find('.no-drafts').addClass('hidden');
166
+ draftListEl.find('.placeholder-wave').addClass('hidden');
167
+ draftListEl.find('.draft-item-container').html(html).find('.timeago').timeago();
168
+ }
169
+
170
+
171
+ draftsEl.on('shown.bs.dropdown', renderDraftList);
172
+
173
+ draftsEl.on('click', '[component="drafts/open"]', function () {
174
+ drafts.open($(this).attr('data-save-id'));
175
+ });
176
+
177
+ draftsEl.on('click', '[component="drafts/delete"]', function () {
178
+ const save_id = $(this).attr('data-save-id');
179
+ bootbox.confirm('[[modules:composer.discard-draft-confirm]]', function (ok) {
180
+ if (ok) {
181
+ drafts.removeDraft(save_id);
182
+ renderDraftList();
183
+ }
184
+ });
185
+ return false;
186
+ });
187
+
188
+ $(window).on('action:composer.drafts.save', updateBadgeCount);
189
+ $(window).on('action:composer.drafts.remove', updateBadgeCount);
190
+ updateBadgeCount();
191
+ });
192
+ }
193
+
194
+ function setupNProgress() {
195
+ require(['nprogress'], function (NProgress) {
196
+ window.nprogress = NProgress;
197
+ if (NProgress) {
198
+ $(window).on('action:ajaxify.start', function () {
199
+ NProgress.set(0.7);
200
+ });
201
+
202
+ $(window).on('action:ajaxify.end', function () {
203
+ NProgress.done(true);
204
+ });
205
+ }
206
+ });
207
+ }
208
+
209
+ function handleMobileNavigator() {
210
+ const paginationBlockEl = $('.pagination-block');
211
+ require(['hooks'], function (hooks) {
212
+ hooks.on('action:ajaxify.end', function () {
213
+ paginationBlockEl.find('.dropdown-menu.show').removeClass('show');
214
+ });
215
+ hooks.on('filter:navigator.scroll', function (hookData) {
216
+ paginationBlockEl.find('.dropdown-menu.show').removeClass('show');
217
+ return hookData;
218
+ });
219
+ });
220
+ }
221
+
222
+ function setupNavTooltips() {
223
+ // remove title from user icon in sidebar to prevent double tooltip
224
+ $('.sidebar [component="header/avatar"] .avatar').removeAttr('title');
225
+ const tooltipEls = $('.sidebar [title]');
226
+ const lefttooltipEls = $('.sidebar-left [title]');
227
+ const rightooltipEls = $('.sidebar-right [title]');
228
+ const isRtl = $('html').attr('data-dir') === 'rtl';
229
+ lefttooltipEls.tooltip({
230
+ trigger: 'manual',
231
+ animation: false,
232
+ placement: isRtl ? 'left' : 'right',
233
+ });
234
+ rightooltipEls.tooltip({
235
+ trigger: 'manual',
236
+ animation: false,
237
+ placement: isRtl ? 'right' : 'left',
238
+ });
239
+
240
+ tooltipEls.on('mouseenter', function (ev) {
241
+ const target = $(ev.target);
242
+ const isDropdown = target.hasClass('dropdown-menu') || !!target.parents('.dropdown-menu').length;
243
+ if (!$('.sidebar').hasClass('open') && !isDropdown) {
244
+ $(this).tooltip('show');
245
+ }
246
+ });
247
+ tooltipEls.on('click mouseleave', function () {
248
+ $(this).tooltip('hide');
249
+ });
250
+ }
251
+
252
+ function fixPlaceholders() {
253
+ if (!config.loggedIn) {
254
+ return;
255
+ }
256
+ ['notifications', 'chat'].forEach((type) => {
257
+ const countEl = $(`nav.sidebar [component="${type}/count"]`).first();
258
+ if (!countEl.length) {
259
+ return;
260
+ }
261
+ const count = parseInt(countEl.text(), 10);
262
+ if (count > 1) {
263
+ const listEls = $(`.dropdown-menu [component="${type}/list"]`);
264
+ listEls.each((index, el) => {
265
+ const placeholder = $(el).children().first();
266
+ for (let x = 0; x < count - 1; x++) {
267
+ const cloneEl = placeholder.clone(true);
268
+ cloneEl.insertAfter(placeholder);
269
+ }
270
+ });
271
+ }
272
+ });
273
+ }
274
+
275
+ function fixSidebarOverflow() {
276
+ // overflow-y-auto needs to be removed on main-nav when dropdowns are opened
277
+ const mainNavEl = $('#main-nav');
278
+ function toggleOverflow() {
279
+ mainNavEl.toggleClass(
280
+ 'overflow-y-auto',
281
+ !mainNavEl.find('.dropdown-menu.show').length
282
+ );
283
+ }
284
+ mainNavEl.on('shown.bs.dropdown', toggleOverflow)
285
+ .on('hidden.bs.dropdown', toggleOverflow);
286
+ }
287
+ });
@@ -1,31 +1,31 @@
1
- 'use strict';
2
-
3
- define('forum/account/theme', ['forum/account/header', 'api', 'settings', 'alerts'], function (header, api, settings, alerts) {
4
- const Theme = {};
5
-
6
- Theme.init = () => {
7
- header.init();
8
- Theme.setupForm();
9
- };
10
-
11
- Theme.setupForm = () => {
12
- const saveEl = document.getElementById('save');
13
- if (saveEl) {
14
- const formEl = document.getElementById('theme-settings');
15
- saveEl.addEventListener('click', async () => {
16
- const themeSettings = settings.helper.serializeForm($(formEl));
17
- await api.put(`/users/${ajaxify.data.uid}/settings`, {
18
- settings: {
19
- ...themeSettings,
20
- },
21
- });
22
- if (ajaxify.data.isSelf) {
23
- config.theme = (await api.get('/api/config')).theme;
24
- }
25
- alerts.success('[[success:settings-saved]]');
26
- });
27
- }
28
- };
29
-
30
- return Theme;
31
- });
1
+ 'use strict';
2
+
3
+ define('forum/account/theme', ['forum/account/header', 'api', 'settings', 'alerts'], function (header, api, settings, alerts) {
4
+ const Theme = {};
5
+
6
+ Theme.init = () => {
7
+ header.init();
8
+ Theme.setupForm();
9
+ };
10
+
11
+ Theme.setupForm = () => {
12
+ const saveEl = document.getElementById('save');
13
+ if (saveEl) {
14
+ const formEl = document.getElementById('theme-settings');
15
+ saveEl.addEventListener('click', async () => {
16
+ const themeSettings = settings.helper.serializeForm($(formEl));
17
+ await api.put(`/users/${ajaxify.data.uid}/settings`, {
18
+ settings: {
19
+ ...themeSettings,
20
+ },
21
+ });
22
+ if (ajaxify.data.isSelf) {
23
+ config.theme = (await api.get('/api/config')).theme;
24
+ }
25
+ alerts.success('[[success:settings-saved]]');
26
+ });
27
+ }
28
+ };
29
+
30
+ return Theme;
31
+ });