You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

802 lines
24 KiB

3 years ago
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
  1. /*
  2. * Document : template.js
  3. * Author : pixelcave
  4. * Description: UI Framework custom functionality
  5. *
  6. */
  7. // Imports
  8. import * as bootstrap from 'bootstrap';
  9. import SimpleBar from 'simplebar';
  10. import Helpers from './helpers';
  11. // Assignments
  12. window.bootstrap = bootstrap;
  13. window.SimpleBar = SimpleBar;
  14. // Template
  15. export default class Template {
  16. /*
  17. * Auto called when creating a new instance
  18. *
  19. */
  20. constructor() {
  21. this.onLoad(() => this._uiInit());
  22. }
  23. /*
  24. * Init all vital functionality
  25. *
  26. */
  27. _uiInit() {
  28. // Layout variables
  29. this._lHtml = document.documentElement;
  30. this._lBody = document.body;
  31. this._lpageLoader = document.getElementById('page-loader');
  32. this._lPage = document.getElementById('page-container');
  33. this._lSidebar = document.getElementById('sidebar');
  34. this._lSidebarScrollCon = this._lSidebar && this._lSidebar.querySelector('.js-sidebar-scroll');
  35. this._lSideOverlay = document.getElementById('side-overlay');
  36. this._lResize = false;
  37. this._lHeader = document.getElementById('page-header');
  38. this._lHeaderSearch = document.getElementById('page-header-search');
  39. this._lHeaderSearchInput = document.getElementById('page-header-search-input');
  40. this._lHeaderLoader = document.getElementById('page-header-loader');
  41. this._lMain = document.getElementById('main-container');
  42. this._lFooter = document.getElementById('page-footer');
  43. // Helper variables
  44. this._lSidebarScroll = false;
  45. this._lSideOverlayScroll = false;
  46. // Base UI Init
  47. this._uiHandleTheme();
  48. this._uiHandleDarkMode();
  49. this._uiHandleSidebars();
  50. this._uiHandleHeader();
  51. this._uiHandleNav();
  52. // API Init
  53. this._uiApiLayout();
  54. this._uiApiBlocks();
  55. // Init the following helpers by default
  56. this.helpers([
  57. 'bs-tooltip',
  58. 'bs-popover',
  59. 'dm-toggle-class',
  60. 'dm-year-copy',
  61. 'dm-ripple',
  62. ]);
  63. // Page Loader (hide it)
  64. this._uiHandlePageLoader();
  65. }
  66. /*
  67. * Handles sidebar and side overlay scrolling functionality/styles
  68. *
  69. */
  70. _uiHandleSidebars(mode = 'init') {
  71. let self = this;
  72. if (self._lSidebar || self._lSideOverlay) {
  73. if (mode === 'init') {
  74. // Add 'side-trans-enabled' class to #page-container (enables sidebar and side overlay transition on open/close)
  75. // Fixes IE10, IE11 and Edge bug in which animation was executed on each page load
  76. self._lPage.classList.add('side-trans-enabled');
  77. // Remove side transitions on window resizing
  78. window.addEventListener('resize', () => {
  79. clearTimeout(self._lResize);
  80. self._lPage.classList.remove('side-trans-enabled');
  81. self._lResize = setTimeout(() => { self._lPage.classList.add('side-trans-enabled'); }, 500);
  82. });
  83. // Init custom scrolling
  84. this._uiHandleSidebars('custom-scroll');
  85. } else if (mode = 'custom-scroll') {
  86. // If .side-scroll is added to #page-container, enable custom scrolling
  87. if (self._lPage.classList.contains('side-scroll')) {
  88. // Init custom scrolling on Sidebar
  89. if ((self._lSidebar) && !self._lSidebarScroll) {
  90. self._lSidebarScroll = new SimpleBar(self._lSidebarScrollCon);
  91. }
  92. // Init custom scrolling on Side Overlay
  93. if ((self._lSideOverlay) && !self._lSideOverlayScroll) {
  94. self._lSideOverlayScroll = new SimpleBar(self._lSideOverlay);
  95. }
  96. }
  97. }
  98. }
  99. }
  100. /*
  101. * Handles header related classes
  102. *
  103. */
  104. _uiHandleHeader() {
  105. let self = this;
  106. // If the header is fixed and has the glass style, add the related class on scrolling to add a background color to the header
  107. if (self._lPage.classList.contains('page-header-glass') && self._lPage.classList.contains('page-header-fixed')) {
  108. window.addEventListener('scroll', e => {
  109. if (window.scrollY > 60) {
  110. self._lPage.classList.add('page-header-scroll');
  111. } else {
  112. self._lPage.classList.remove('page-header-scroll');
  113. }
  114. });
  115. window.dispatchEvent(new CustomEvent('scroll'));
  116. }
  117. }
  118. /*
  119. * Toggle Submenu functionality
  120. *
  121. */
  122. _uiHandleNav() {
  123. let links = document.querySelectorAll('[data-toggle="submenu"]');
  124. // When a submenu link is clicked
  125. if (links) {
  126. links.forEach(link => {
  127. link.addEventListener('click', e => {
  128. e.preventDefault();
  129. // Get main navigation
  130. let mainNav = link.closest('.nav-main');
  131. // Check if we are in horizontal navigation, large screen and hover is enabled
  132. if (
  133. !(
  134. (window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth) > 991
  135. && mainNav.classList.contains('nav-main-horizontal')
  136. && mainNav.classList.contains('nav-main-hover')
  137. )
  138. ) {
  139. // Get link's parent
  140. let parentLi = link.closest('li');
  141. if (parentLi.classList.contains('open')) {
  142. // If submenu is open, close it..
  143. parentLi.classList.remove('open');
  144. link.setAttribute('aria-expanded', 'false');
  145. } else {
  146. // .. else if submenu is closed, close all other (same level) submenus first before open it
  147. Array.from(link.closest('ul').children).forEach(el => {
  148. el.classList.remove('open');
  149. });
  150. parentLi.classList.add('open');
  151. link.setAttribute('aria-expanded', 'true');
  152. }
  153. }
  154. return false;
  155. });
  156. });
  157. }
  158. }
  159. /*
  160. * Page loading screen functionality
  161. *
  162. */
  163. _uiHandlePageLoader(mode = 'hide', colorClass) {
  164. if (mode === 'show') {
  165. if (this._lpageLoader) {
  166. if (colorClass) {
  167. this._lpageLoader.className = '';
  168. this._lpageLoader.classList.add(colorClass);
  169. }
  170. this._lpageLoader.classList.add('show');
  171. } else {
  172. let pageLoader = document.createElement('div');
  173. pageLoader.id = 'page-loader';
  174. if (colorClass) {
  175. pageLoader.classList.add(colorClass);
  176. }
  177. pageLoader.classList.add('show');
  178. this._lPage.insertBefore(pageLoader, this._lPage.firstChild);
  179. this._lpageLoader = document.getElementById('page-loader');
  180. }
  181. } else if (mode === 'hide') {
  182. if (this._lpageLoader) {
  183. this._lpageLoader.classList.remove('show');
  184. }
  185. }
  186. }
  187. /*
  188. * Saves/Retrieves Dark Mode preference to local storage
  189. *
  190. */
  191. _uiHandleDarkMode(mode = 'init') {
  192. let self = this;
  193. // If dark mode is not enabled by default remember default sidebar
  194. // and header style to return to after any possible dark mode disabling
  195. if (mode === 'init' && !self._lPage.classList.contains('dark-mode')) {
  196. if (self._lPage.classList.contains('sidebar-dark')) {
  197. localStorage.setItem('dashmixDefaultsSidebarDark', true);
  198. } else {
  199. localStorage.removeItem('dashmixDefaultsSidebarDark');
  200. }
  201. if (self._lPage.classList.contains('page-header-dark')) {
  202. localStorage.setItem('dashmixDefaultsPageHeaderDark', true);
  203. } else {
  204. localStorage.removeItem('dashmixDefaultsPageHeaderDark');
  205. }
  206. }
  207. // If remember-theme class is added in #page-container
  208. if (self._lPage.classList.contains('remember-theme')) {
  209. let darkMode = localStorage.getItem('dashmixDarkMode') || false;
  210. if (mode === 'init') {
  211. if (darkMode) {
  212. self._lPage.classList.add('sidebar-dark');
  213. self._lPage.classList.add('page-header-dark');
  214. self._lPage.classList.add('dark-mode');
  215. } else if (mode === 'init') {
  216. self._lPage.classList.remove('dark-mode');
  217. }
  218. } else if (mode === 'on') {
  219. localStorage.setItem('dashmixDarkMode', true);
  220. } else if (mode === 'off') {
  221. localStorage.removeItem('dashmixDarkMode');
  222. }
  223. } else if (mode === 'init') {
  224. localStorage.removeItem('dashmixDarkMode');
  225. }
  226. }
  227. /*
  228. * Set active color theme functionality
  229. *
  230. */
  231. _uiHandleTheme() {
  232. let self = this;
  233. let themeEl = document.getElementById('css-theme');
  234. let rememberTheme = this._lPage.classList.contains('remember-theme') ? true : false;
  235. // If remember theme is enabled
  236. if (rememberTheme) {
  237. let themeName = localStorage.getItem('dashmixThemeName') || false;
  238. // Update color theme
  239. if (themeName) {
  240. self._uiUpdateTheme(themeEl, themeName);
  241. }
  242. // Update theme element
  243. themeEl = document.getElementById('css-theme');
  244. } else {
  245. localStorage.removeItem('dashmixThemeName');
  246. }
  247. // Set the active color theme link as active
  248. document.querySelectorAll('[data-toggle="theme"][data-theme="' + (themeEl ? themeEl.getAttribute('href') : 'default') + '"]').forEach(link => {
  249. link.classList.add('active');
  250. });
  251. // When a color theme link is clicked
  252. document.querySelectorAll('[data-toggle="theme"]').forEach(el => {
  253. el.addEventListener('click', e => {
  254. e.preventDefault();
  255. // Get element's data
  256. let themeName = el.dataset.theme;
  257. // Set this color theme link as active
  258. document.querySelectorAll('[data-toggle="theme"]').forEach(link => {
  259. link.classList.remove('active');
  260. });
  261. document.querySelector('[data-toggle="theme"][data-theme="' + themeName + '"]').classList.add('active');
  262. // Update color theme
  263. self._uiUpdateTheme(themeEl, themeName);
  264. // Update theme element
  265. themeEl = document.getElementById('css-theme');
  266. // If remember theme is enabled, save the new active color theme
  267. if (rememberTheme) {
  268. localStorage.setItem('dashmixThemeName', themeName);
  269. }
  270. });
  271. });
  272. }
  273. /*
  274. * Updates the color theme
  275. *
  276. */
  277. _uiUpdateTheme(themeEl, themeName) {
  278. if (themeName === 'default') {
  279. if (themeEl) {
  280. themeEl.parentNode.removeChild(themeEl);
  281. }
  282. } else {
  283. if (themeEl) {
  284. themeEl.setAttribute('href', themeName);
  285. } else {
  286. let themeLink = document.createElement('link');
  287. themeLink.id = 'css-theme';
  288. themeLink.setAttribute('rel', 'stylesheet');
  289. themeLink.setAttribute('href', themeName);
  290. document.getElementById('css-main').insertAdjacentElement('afterend', themeLink);
  291. }
  292. }
  293. }
  294. /*
  295. * Layout API
  296. *
  297. */
  298. _uiApiLayout(mode = 'init') {
  299. let self = this;
  300. // API with object literals
  301. let layoutAPI = {
  302. init: () => {
  303. let buttons = document.querySelectorAll('[data-toggle="layout"]');
  304. // Call layout API on button click
  305. if (buttons) {
  306. buttons.forEach(btn => {
  307. btn.addEventListener('click', e => {
  308. self._uiApiLayout(btn.dataset.action);
  309. });
  310. })
  311. }
  312. // Prepend Page Overlay div if enabled (used when Side Overlay opens)
  313. if (self._lPage.classList.contains('enable-page-overlay')) {
  314. let pageOverlay = document.createElement('div');
  315. pageOverlay.id = 'page-overlay';
  316. self._lPage.insertBefore(pageOverlay, self._lPage.firstChild);
  317. document.getElementById('page-overlay').addEventListener('click', e => {
  318. self._uiApiLayout('side_overlay_close');
  319. });
  320. }
  321. },
  322. sidebar_pos_toggle: () => {
  323. self._lPage.classList.toggle('sidebar-r');
  324. },
  325. sidebar_pos_left: () => {
  326. self._lPage.classList.remove('sidebar-r');
  327. },
  328. sidebar_pos_right: () => {
  329. self._lPage.classList.add('sidebar-r');
  330. },
  331. sidebar_toggle: () => {
  332. if (window.innerWidth > 991) {
  333. self._lPage.classList.toggle('sidebar-o');
  334. } else {
  335. self._lPage.classList.toggle('sidebar-o-xs');
  336. }
  337. },
  338. sidebar_open: () => {
  339. if (window.innerWidth > 991) {
  340. self._lPage.classList.add('sidebar-o');
  341. } else {
  342. self._lPage.classList.add('sidebar-o-xs');
  343. }
  344. },
  345. sidebar_close: () => {
  346. if (window.innerWidth > 991) {
  347. self._lPage.classList.remove('sidebar-o');
  348. } else {
  349. self._lPage.classList.remove('sidebar-o-xs');
  350. }
  351. },
  352. sidebar_mini_toggle: () => {
  353. if (window.innerWidth > 991) {
  354. self._lPage.classList.toggle('sidebar-mini');
  355. }
  356. },
  357. sidebar_mini_on: () => {
  358. if (window.innerWidth > 991) {
  359. self._lPage.classList.add('sidebar-mini');
  360. }
  361. },
  362. sidebar_mini_off: () => {
  363. if (window.innerWidth > 991) {
  364. self._lPage.classList.remove('sidebar-mini');
  365. }
  366. },
  367. sidebar_style_toggle: () => {
  368. if (self._lPage.classList.contains('sidebar-dark')) {
  369. self._uiApiLayout('sidebar_style_light');
  370. } else {
  371. self._uiApiLayout('sidebar_style_dark');
  372. }
  373. },
  374. sidebar_style_dark: () => {
  375. self._lPage.classList.add('sidebar-dark');
  376. localStorage.setItem('dashmixDefaultsSidebarDark', true);
  377. },
  378. sidebar_style_light: () => {
  379. self._lPage.classList.remove('sidebar-dark');
  380. self._lPage.classList.remove('dark-mode');
  381. localStorage.removeItem('dashmixDefaultsSidebarDark');
  382. },
  383. side_overlay_toggle: () => {
  384. if (self._lPage.classList.contains('side-overlay-o')) {
  385. self._uiApiLayout('side_overlay_close');
  386. } else {
  387. self._uiApiLayout('side_overlay_open');
  388. }
  389. },
  390. side_overlay_open: () => {
  391. // When ESCAPE key is hit close the side overlay
  392. document.addEventListener('keydown', e => {
  393. if (e.key === 'Esc' || e.key === 'Escape') {
  394. self._uiApiLayout('side_overlay_close');
  395. }
  396. });
  397. self._lPage.classList.add('side-overlay-o');
  398. },
  399. side_overlay_close: () => {
  400. self._lPage.classList.remove('side-overlay-o');
  401. },
  402. side_overlay_mode_hover_toggle: () => {
  403. self._lPage.classList.toggle('side-overlay-hover');
  404. },
  405. side_overlay_mode_hover_on: () => {
  406. self._lPage.classList.add('side-overlay-hover');
  407. },
  408. side_overlay_mode_hover_off: () => {
  409. self._lPage.classList.remove('side-overlay-hover');
  410. },
  411. header_glass_toggle: () => {
  412. self._lPage.classList.toggle('page-header-glass');
  413. self._uiHandleHeader();
  414. },
  415. header_glass_on: () => {
  416. self._lPage.classList.add('page-header-glass');
  417. self._uiHandleHeader();
  418. },
  419. header_glass_off: () => {
  420. self._lPage.classList.remove('page-header-glass');
  421. self._uiHandleHeader();
  422. },
  423. header_mode_toggle: () => {
  424. self._lPage.classList.toggle('page-header-fixed');
  425. },
  426. header_mode_static: () => {
  427. self._lPage.classList.remove('page-header-fixed');
  428. },
  429. header_mode_fixed: () => {
  430. self._lPage.classList.add('page-header-fixed');
  431. },
  432. header_style_toggle: () => {
  433. if (self._lPage.classList.contains('page-header-dark')) {
  434. self._uiApiLayout('header_style_light');
  435. } else {
  436. self._uiApiLayout('header_style_dark');
  437. }
  438. },
  439. header_style_dark: () => {
  440. self._lPage.classList.add('page-header-dark');
  441. localStorage.setItem('dashmixDefaultsPageHeaderDark', true);
  442. },
  443. header_style_light: () => {
  444. self._lPage.classList.remove('page-header-dark');
  445. self._lPage.classList.remove('dark-mode');
  446. localStorage.removeItem('dashmixDefaultsPageHeaderDark');
  447. },
  448. header_search_on: () => {
  449. self._lHeaderSearch.classList.add('show');
  450. self._lHeaderSearchInput.focus();
  451. // When ESCAPE key is hit close the search section
  452. document.addEventListener('keydown', e => {
  453. if (e.key === 'Esc' || e.key === 'Escape') {
  454. self._uiApiLayout('header_search_off');
  455. }
  456. });
  457. },
  458. header_search_off: () => {
  459. self._lHeaderSearch.classList.remove('show');
  460. self._lHeaderSearchInput.blur();
  461. },
  462. header_loader_on: () => {
  463. self._lHeaderLoader.classList.add('show');
  464. },
  465. header_loader_off: () => {
  466. self._lHeaderLoader.classList.remove('show');
  467. },
  468. dark_mode_toggle: () => {
  469. if (self._lPage.classList.contains('dark-mode')) {
  470. self._uiApiLayout('dark_mode_off');
  471. } else {
  472. self._uiApiLayout('dark_mode_on');
  473. }
  474. },
  475. dark_mode_on: () => {
  476. self._lPage.classList.add('sidebar-dark');
  477. self._lPage.classList.add('page-header-dark');
  478. self._lPage.classList.add('dark-mode');
  479. this._uiHandleDarkMode('on');
  480. },
  481. dark_mode_off: () => {
  482. if (!localStorage.getItem('dashmixDefaultsSidebarDark')) {
  483. self._lPage.classList.remove('sidebar-dark');
  484. }
  485. if (!localStorage.getItem('dashmixDefaultsPageHeaderDark')) {
  486. self._lPage.classList.remove('page-header-dark');
  487. }
  488. self._lPage.classList.remove('dark-mode');
  489. this._uiHandleDarkMode('off');
  490. },
  491. content_layout_toggle: () => {
  492. if (self._lPage.classList.contains('main-content-boxed')) {
  493. self._uiApiLayout('content_layout_narrow');
  494. } else if (self._lPage.classList.contains('main-content-narrow')) {
  495. self._uiApiLayout('content_layout_full_width');
  496. } else {
  497. self._uiApiLayout('content_layout_boxed');
  498. }
  499. },
  500. content_layout_boxed: () => {
  501. self._lPage.classList.remove('main-content-narrow');
  502. self._lPage.classList.add('main-content-boxed');
  503. },
  504. content_layout_narrow: () => {
  505. self._lPage.classList.remove('main-content-boxed');
  506. self._lPage.classList.add('main-content-narrow');
  507. },
  508. content_layout_full_width: () => {
  509. self._lPage.classList.remove('main-content-boxed');
  510. self._lPage.classList.remove('main-content-narrow');
  511. }
  512. };
  513. // Call layout API
  514. if (layoutAPI[mode]) {
  515. layoutAPI[mode]();
  516. }
  517. }
  518. /*
  519. * Blocks API
  520. *
  521. */
  522. _uiApiBlocks(mode = 'init', block = false) {
  523. let self = this;
  524. // Helper variables
  525. let elBlock, btnFullscreen, btnContentToggle;
  526. // Set default icons for fullscreen and content toggle buttons
  527. let iconBase = 'si';
  528. let iconFullscreen = 'si-size-fullscreen';
  529. let iconFullscreenActive = 'si-size-actual';
  530. let iconContent = 'si-arrow-up';
  531. let iconContentActive = 'si-arrow-down';
  532. // API with object literals
  533. let blockAPI = {
  534. init: () => {
  535. // Auto add the default toggle icons to fullscreen and content toggle buttons
  536. document.querySelectorAll('[data-toggle="block-option"][data-action="fullscreen_toggle"]').forEach(btn => {
  537. btn.innerHTML = '<i class="' + iconBase + ' ' + (btn.closest('.block').classList.contains('block-mode-fullscreen') ? iconFullscreenActive : iconFullscreen) + '"></i>';
  538. });
  539. document.querySelectorAll('[data-toggle="block-option"][data-action="content_toggle"]').forEach(btn => {
  540. btn.innerHTML = '<i class="' + iconBase + ' ' + (btn.closest('.block').classList.contains('block-mode-hidden') ? iconContentActive : iconContent) + '"></i>';
  541. });
  542. // Call blocks API on option button click
  543. document.querySelectorAll('[data-toggle="block-option"]').forEach(btn => {
  544. btn.addEventListener('click', e => {
  545. this._uiApiBlocks(btn.dataset.action, btn.closest('.block'));
  546. });
  547. });
  548. },
  549. fullscreen_toggle: () => {
  550. elBlock.classList.remove('block-mode-pinned');
  551. elBlock.classList.toggle('block-mode-fullscreen');
  552. // Update block option icon
  553. if (btnFullscreen) {
  554. if (elBlock.classList.contains('block-mode-fullscreen')) {
  555. btnFullscreen && btnFullscreen.querySelector('i').classList.replace(iconFullscreen, iconFullscreenActive);
  556. } else {
  557. btnFullscreen && btnFullscreen.querySelector('i').classList.replace(iconFullscreenActive, iconFullscreen);
  558. }
  559. }
  560. },
  561. fullscreen_on: () => {
  562. elBlock.classList.remove('block-mode-pinned')
  563. elBlock.classList.add('block-mode-fullscreen');
  564. // Update block option icon
  565. btnFullscreen && btnFullscreen.querySelector('i').classList.replace(iconFullscreen, iconFullscreenActive);
  566. },
  567. fullscreen_off: () => {
  568. elBlock.classList.remove('block-mode-fullscreen');
  569. // Update block option icon
  570. btnFullscreen && btnFullscreen.querySelector('i').classList.replace(iconFullscreenActive, iconFullscreen);
  571. },
  572. content_toggle: () => {
  573. elBlock.classList.toggle('block-mode-hidden');
  574. // Update block option icon
  575. if (btnContentToggle) {
  576. if (elBlock.classList.contains('block-mode-hidden')) {
  577. btnContentToggle.querySelector('i').classList.replace(iconContent, iconContentActive);
  578. } else {
  579. btnContentToggle.querySelector('i').classList.replace(iconContentActive, iconContent);
  580. }
  581. }
  582. },
  583. content_hide: () => {
  584. elBlock.classList.add('block-mode-hidden');
  585. // Update block option icon
  586. btnContentToggle && btnContentToggle.querySelector('i').classList.replace(iconContent, iconContentActive);
  587. },
  588. content_show: () => {
  589. elBlock.classList.remove('block-mode-hidden');
  590. // Update block option icon
  591. btnContentToggle && btnContentToggle.querySelector('i').classList.replace(iconContentActive, iconContent);
  592. },
  593. state_toggle: () => {
  594. elBlock.classList.toggle('block-mode-loading');
  595. // Return block to normal state if the demostration mode is on in the refresh option button - data-action-mode="demo"
  596. if (elBlock.querySelector('[data-toggle="block-option"][data-action="state_toggle"][data-action-mode="demo"]')) {
  597. setTimeout(() => {
  598. elBlock.classList.remove('block-mode-loading');
  599. }, 2000);
  600. }
  601. },
  602. state_loading: () => {
  603. elBlock.classList.add('block-mode-loading');
  604. },
  605. state_normal: () => {
  606. elBlock.classList.remove('block-mode-loading');
  607. },
  608. pinned_toggle: () => {
  609. elBlock.classList.remove('block-mode-fullscreen');
  610. elBlock.classList.toggle('block-mode-pinned');
  611. },
  612. pinned_on: () => {
  613. elBlock.classList.remove('block-mode-fullscreen');
  614. elBlock.classList.add('block-mode-pinned');
  615. },
  616. pinned_off: () => {
  617. elBlock.classList.remove('block-mode-pinned');
  618. },
  619. close: () => {
  620. elBlock.classList.add('d-none');
  621. },
  622. open: () => {
  623. elBlock.classList.remove('d-none');
  624. }
  625. };
  626. if (mode === 'init') {
  627. // Call Block API
  628. blockAPI[mode]();
  629. } else {
  630. // Get block element
  631. elBlock = (block instanceof Element) ? block : document.querySelector(`${block}`);
  632. // If element exists, procceed with block functionality
  633. if (elBlock) {
  634. // Get block option buttons if exist (need them to update their icons)
  635. btnFullscreen = elBlock.querySelector('[data-toggle="block-option"][data-action="fullscreen_toggle"]');
  636. btnContentToggle = elBlock.querySelector('[data-toggle="block-option"][data-action="content_toggle"]');
  637. // Call Block API
  638. if (blockAPI[mode]) {
  639. blockAPI[mode]();
  640. }
  641. }
  642. }
  643. }
  644. /*
  645. ********************************************************************************************
  646. *
  647. * Helpers
  648. *
  649. *********************************************************************************************
  650. */
  651. /*
  652. * On DOM content loaded
  653. *
  654. */
  655. onLoad(fn) {
  656. if (document.readyState != 'loading') {
  657. fn();
  658. } else {
  659. document.addEventListener('DOMContentLoaded', fn);
  660. }
  661. }
  662. /*
  663. ********************************************************************************************
  664. *
  665. * Create aliases for easier/quicker access to vital methods
  666. *
  667. *********************************************************************************************
  668. */
  669. /*
  670. * Init base functionality
  671. *
  672. */
  673. init() {
  674. this._uiInit();
  675. }
  676. /*
  677. * Layout API
  678. *
  679. */
  680. layout(mode) {
  681. this._uiApiLayout(mode);
  682. }
  683. /*
  684. * Blocks API
  685. *
  686. */
  687. block(mode, block) {
  688. this._uiApiBlocks(mode, block);
  689. }
  690. /*
  691. * Handle Page Loader
  692. *
  693. */
  694. loader(mode, colorClass) {
  695. this._uiHandlePageLoader(mode, colorClass);
  696. }
  697. /*
  698. * Run Helpers
  699. *
  700. */
  701. helpers(helpers, options = {}) {
  702. Helpers.run(helpers, options);
  703. }
  704. /*
  705. * Run Helpers on DOM content loaded
  706. *
  707. */
  708. helpersOnLoad(helpers, options = {}) {
  709. this.onLoad(() => Helpers.run(helpers, options));
  710. }
  711. }