Nav apraksta
Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359
  1. /**
  2. * App Email
  3. */
  4. 'use strict';
  5. document.addEventListener('DOMContentLoaded', function () {
  6. (function () {
  7. // Utility function to initialize PerfectScrollbar
  8. const initPerfectScrollbar = (element, options = { wheelPropagation: false, suppressScrollX: true }) => {
  9. if (element) new PerfectScrollbar(element, options);
  10. };
  11. // Query selectors for elements and collections
  12. const selectors = {
  13. emailList: document.querySelector('.email-list'),
  14. emailListItems: Array.from(document.querySelectorAll('.email-list-item')),
  15. emailListItemInputs: Array.from(document.querySelectorAll('.email-list-item-input')),
  16. emailView: document.querySelector('.app-email-view-content'),
  17. emailFilters: document.querySelector('.email-filters'),
  18. emailFilterByFolders: Array.from(document.querySelectorAll('.email-filter-folders li')),
  19. emailEditor: document.querySelector('.email-editor'),
  20. appEmailSidebar: document.querySelector('.app-email-sidebar'),
  21. appOverlay: document.querySelector('.app-overlay'),
  22. emailReplyEditor: document.querySelector('.email-reply-editor'),
  23. bookmarkEmail: Array.from(document.querySelectorAll('.email-list-item-bookmark')),
  24. selectAllEmails: document.getElementById('email-select-all'),
  25. emailSearch: document.querySelector('.email-search-input'),
  26. toggleCC: document.querySelector('.email-compose-toggle-cc'),
  27. toggleBCC: document.querySelector('.email-compose-toggle-bcc'),
  28. emailCompose: document.querySelector('.app-email-compose'),
  29. emailListDelete: document.querySelector('.email-list-delete'),
  30. emailListRead: document.querySelector('.email-list-read'),
  31. emailListEmpty: document.querySelector('.email-list-empty'),
  32. refreshEmails: document.querySelector('.email-refresh'),
  33. emailViewContainer: document.getElementById('app-email-view'),
  34. emailFilterFolderLists: Array.from(document.querySelectorAll('.email-filter-folders li')),
  35. emailListItemActions: Array.from(document.querySelectorAll('.email-list-item-actions li'))
  36. };
  37. // Initialize scrollbars where needed
  38. initPerfectScrollbar(selectors.emailList);
  39. initPerfectScrollbar(selectors.emailFilters);
  40. initPerfectScrollbar(selectors.emailView);
  41. // Utility function to initialize Quill Editor
  42. const initQuillEditor = (selector, toolbar) => {
  43. if (selector) {
  44. new Quill(selector, {
  45. modules: { toolbar },
  46. placeholder: 'Write your message...',
  47. theme: 'snow'
  48. });
  49. }
  50. };
  51. // Initialize editors
  52. initQuillEditor(selectors.emailEditor, '.email-editor-toolbar');
  53. initQuillEditor(selectors.emailReplyEditor, '.email-reply-toolbar');
  54. // Bookmark email functionality
  55. selectors.bookmarkEmail.forEach(emailItem => {
  56. emailItem.addEventListener('click', e => {
  57. const emailItemParent = e.currentTarget.closest('.email-list-item');
  58. e.stopPropagation();
  59. if (emailItemParent.hasAttribute('data-starred')) {
  60. // If attribute exists, remove it
  61. emailItemParent.removeAttribute('data-starred');
  62. } else {
  63. // If attribute does not exist, set it with the value "true"
  64. emailItemParent.setAttribute('data-starred', 'true');
  65. }
  66. });
  67. });
  68. // Select all functionality
  69. if (selectors.selectAllEmails) {
  70. selectors.selectAllEmails.addEventListener('click', e => {
  71. selectors.emailListItemInputs.forEach(input => {
  72. input.checked = e.currentTarget.checked;
  73. });
  74. });
  75. }
  76. // Select single email and update 'Select All' checkbox state
  77. if (selectors.emailListItemInputs) {
  78. selectors.emailListItemInputs.forEach(emailListItemInput => {
  79. emailListItemInput.addEventListener('click', e => {
  80. e.stopPropagation();
  81. // Count checked inputs
  82. const checkedCount = selectors.emailListItemInputs.filter(input => input.checked).length;
  83. const totalInputs = selectors.emailListItemInputs.length;
  84. // Update 'Select All' checkbox and indeterminate state
  85. selectors.selectAllEmails.indeterminate = checkedCount > 0 && checkedCount < totalInputs;
  86. selectors.selectAllEmails.checked = checkedCount === totalInputs;
  87. });
  88. });
  89. }
  90. // Search emails based on input text
  91. if (selectors.emailSearch) {
  92. selectors.emailSearch.addEventListener('keyup', e => {
  93. const searchValue = e.currentTarget.value.toLowerCase();
  94. const activeFolderFilter = document.querySelector('.email-filter-folders .active');
  95. const selectedFolder = activeFolderFilter ? activeFolderFilter.getAttribute('data-target') : 'inbox';
  96. // Filter emails based on the active folder
  97. const emailListItems =
  98. selectedFolder !== 'inbox'
  99. ? Array.from(document.querySelectorAll(`.email-list-item[data-${selectedFolder}="true"]`))
  100. : selectors.emailListItems;
  101. // Show/hide emails based on the search term
  102. emailListItems.forEach(emailItem => {
  103. const itemText = emailItem.textContent.toLowerCase();
  104. emailItem.classList.toggle('d-block', itemText.includes(searchValue));
  105. emailItem.classList.toggle('d-none', !itemText.includes(searchValue));
  106. });
  107. });
  108. }
  109. // Filter emails based on folder type (Inbox, Sent, Draft, etc.)
  110. selectors.emailFilterByFolders.forEach(folder => {
  111. folder.addEventListener('click', e => {
  112. const targetFolder = e.currentTarget.getAttribute('data-target');
  113. // Hide sidebar and overlay
  114. selectors.appEmailSidebar.classList.remove('show');
  115. selectors.appOverlay.classList.remove('show');
  116. // Update active class for folder filters
  117. selectors.emailFilterByFolders.forEach(f => f.classList.remove('active'));
  118. e.currentTarget.classList.add('active');
  119. // Filter email items based on selected folder
  120. selectors.emailListItems.forEach(emailItem => {
  121. const matchesFolder = targetFolder === 'inbox' || emailItem.hasAttribute(`data-${targetFolder}`);
  122. emailItem.classList.toggle('d-block', matchesFolder);
  123. emailItem.classList.toggle('d-none', !matchesFolder);
  124. });
  125. });
  126. });
  127. // Toggle visibility of CC/BCC input fields
  128. const toggleVisibility = selector => {
  129. document.querySelector(selector).classList.toggle('d-block');
  130. document.querySelector(selector).classList.toggle('d-none');
  131. };
  132. if (selectors.toggleBCC) {
  133. selectors.toggleBCC.addEventListener('click', () => toggleVisibility('.email-compose-bcc'));
  134. }
  135. if (selectors.toggleCC) {
  136. selectors.toggleCC.addEventListener('click', () => toggleVisibility('.email-compose-cc'));
  137. }
  138. // Clear compose email message inputs when modal is hidden
  139. selectors.emailCompose.addEventListener('hidden.bs.modal', () => {
  140. document.querySelector('.email-editor .ql-editor').innerHTML = '';
  141. document.getElementById('emailContacts').value = '';
  142. initSelect2();
  143. });
  144. // Delete selected emails
  145. if (selectors.emailListDelete) {
  146. selectors.emailListDelete.addEventListener('click', () => {
  147. selectors.emailListItemInputs.forEach(input => {
  148. if (input.checked) {
  149. input.closest('li.email-list-item').remove();
  150. }
  151. });
  152. selectors.selectAllEmails.indeterminate = false;
  153. selectors.selectAllEmails.checked = false;
  154. // Show empty message if no emails are left
  155. if (selectors.emailListItems.length === 0) {
  156. selectors.emailListEmpty.classList.remove('d-none');
  157. }
  158. });
  159. }
  160. // Mark selected emails as read
  161. if (selectors.emailListRead) {
  162. selectors.emailListRead.addEventListener('click', () => {
  163. selectors.emailListItemInputs.forEach(input => {
  164. if (input.checked) {
  165. input.checked = false;
  166. const emailItem = input.closest('li.email-list-item');
  167. emailItem.classList.add('email-marked-read');
  168. // Update envelope icon
  169. const emailActions = emailItem.querySelector('.email-list-item-actions li');
  170. emailActions.classList.replace('email-read', 'email-unread');
  171. const icon = emailActions.querySelector('i');
  172. icon.classList.replace('bx-envelope-open', 'bx-envelope');
  173. }
  174. });
  175. selectors.selectAllEmails.indeterminate = false;
  176. selectors.selectAllEmails.checked = false;
  177. });
  178. }
  179. // Refresh emails with loading animation
  180. if (selectors.refreshEmails && selectors.emailList) {
  181. const emailListClass = '.email-list';
  182. const emailListInstance = new PerfectScrollbar(selectors.emailList, {
  183. wheelPropagation: false,
  184. suppressScrollX: true
  185. });
  186. selectors.refreshEmails.addEventListener('click', () => {
  187. // Block the email list section with Notiflix
  188. Block.standard(emailListClass, {
  189. backgroundColor: 'rgba(' + window.Helpers.getCssVar('black-rgb') + ', 0.1)',
  190. svgSize: '0px'
  191. });
  192. // Add custom spinner to the Notiflix block
  193. const customSpinner = document.createElement('div');
  194. customSpinner.classList.add('spinner-border', 'text-primary');
  195. customSpinner.setAttribute('role', 'status');
  196. const notiflixBlock = document.querySelector('.email-list .notiflix-block');
  197. if (notiflixBlock) {
  198. notiflixBlock.appendChild(customSpinner);
  199. }
  200. // Simulate a timeout and unblock
  201. setTimeout(() => {
  202. // Disable vertical scroll suppression
  203. emailListInstance.settings.suppressScrollY = false;
  204. // Unblock the section
  205. Block.remove(emailListClass);
  206. }, 1000);
  207. // Suppress scroll during the block
  208. emailListInstance.settings.suppressScrollY = true;
  209. });
  210. }
  211. // Toggle visibility of earlier messages
  212. const earlierMsg = document.querySelector('.email-earlier-msgs');
  213. if (earlierMsg) {
  214. earlierMsg.addEventListener('click', () => {
  215. const emailCardLast = document.querySelector('.email-card-last');
  216. const emailCardPrev = earlierMsg.nextElementSibling;
  217. if (emailCardLast) emailCardLast.classList.add('hide-pseudo');
  218. // Vanilla JavaScript slideToggle effect
  219. if (emailCardPrev) {
  220. emailCardPrev.style.display =
  221. emailCardPrev.style.display === 'none' || !emailCardPrev.style.display ? 'block' : 'none';
  222. emailCardPrev.classList.toggle('slide-toggle');
  223. }
  224. // Remove the earlier message link after expanding
  225. earlierMsg.remove();
  226. });
  227. }
  228. // Email contacts (select2)
  229. // ? Using jquery vars due to select2 jQuery dependency
  230. let emailContacts = $('#emailContacts');
  231. function initSelect2() {
  232. if (emailContacts.length) {
  233. function renderContactsAvatar(option) {
  234. if (!option.id) {
  235. return option.text;
  236. }
  237. let $avatar =
  238. "<div class='d-flex flex-wrap align-items-center'>" +
  239. "<div class='avatar avatar-xs me-2 w-px-20 h-px-20'>" +
  240. "<img src='" +
  241. assetsPath +
  242. 'img/avatars/' +
  243. $(option.element).data('avatar') +
  244. "' alt='avatar' class='rounded-circle' />" +
  245. '</div>' +
  246. option.text +
  247. '</div>';
  248. return $avatar;
  249. }
  250. emailContacts.wrap('<div class="position-relative"></div>').select2({
  251. placeholder: 'Select value',
  252. dropdownParent: emailContacts.parent(),
  253. closeOnSelect: false,
  254. templateResult: renderContactsAvatar,
  255. templateSelection: renderContactsAvatar,
  256. escapeMarkup: function (es) {
  257. return es;
  258. }
  259. });
  260. }
  261. }
  262. initSelect2();
  263. // Scroll to bottom on reply click
  264. const emailViewContent = document.querySelector('.app-email-view-content');
  265. const scrollToReplyButton = emailViewContent ? emailViewContent.querySelector('.scroll-to-reply') : null;
  266. if (scrollToReplyButton && emailViewContent) {
  267. scrollToReplyButton.addEventListener('click', () => {
  268. if (emailViewContent.scrollTop === 0) {
  269. // Smooth scroll animation to the bottom
  270. emailViewContent.scrollTo({
  271. top: emailViewContent.scrollHeight,
  272. behavior: 'smooth'
  273. });
  274. }
  275. });
  276. }
  277. // Close view on email filter folder list click
  278. if (selectors.emailFilterFolderLists) {
  279. selectors.emailFilterFolderLists.forEach(folder => {
  280. folder.addEventListener('click', () => {
  281. selectors.emailViewContainer.classList.remove('show');
  282. });
  283. });
  284. }
  285. // Email List Items Actions
  286. if (selectors.emailListItemActions) {
  287. selectors.emailListItemActions.forEach(action => {
  288. action.addEventListener('click', e => {
  289. e.stopPropagation();
  290. const emailItem = action.closest('li.email-list-item');
  291. if (action.classList.contains('email-delete')) {
  292. // Delete email item
  293. emailItem.remove();
  294. // Show empty message if no emails are left
  295. if (!document.querySelectorAll('.email-list-item').length) {
  296. selectors.emailListEmpty.classList.remove('d-none');
  297. }
  298. } else if (action.classList.contains('email-read') || action.classList.contains('email-unread')) {
  299. // Toggle read/unread state
  300. const icon = action.querySelector('i');
  301. emailItem.classList.toggle('email-marked-read', action.classList.contains('email-read'));
  302. action.classList.toggle('email-read');
  303. action.classList.toggle('email-unread');
  304. icon.classList.toggle('bx-envelope-open');
  305. icon.classList.toggle('bx-envelope');
  306. }
  307. });
  308. });
  309. }
  310. })();
  311. });