PageSourceSearch

https://cropmylink.com/assets/js/main.js

js cropmylink.com collected 2026-09-24 14:41:21 UTC 21,991 bytes, 593 lines download raw bytes

1/**
2 * Main
3 */
4
5'use strict';
6
7let isRtl = window.Helpers.isRtl(),
8  isDarkStyle = window.Helpers.isDarkStyle(),
9  menu,
10  animate,
11  isHorizontalLayout = false;
12
13if (document.getElementById('layout-menu')) {
14  isHorizontalLayout = document.getElementById('layout-menu').classList.contains('menu-horizontal');
15}
16
17(function () {
18  // Initialize menu
19  //-----------------
20
21  let layoutMenuEl = document.querySelectorAll('#layout-menu');
22  layoutMenuEl.forEach(function (element) {
23    menu = new Menu(element, {
24      orientation: isHorizontalLayout ? 'horizontal' : 'vertical',
25      closeChildren: isHorizontalLayout ? true : false,
26      // ? This option only works with Horizontal menu
27      showDropdownOnHover: localStorage.getItem('templateCustomizer-' + templateName + '--ShowDropdownOnHover') // If value(showDropdownOnHover) is set in local storage
28        ? localStorage.getItem('templateCustomizer-' + templateName + '--ShowDropdownOnHover') === 'true' // Use the local storage value
29        : window.templateCustomizer !== undefined // If value is set in config.js
30        ? window.templateCustomizer.settings.defaultShowDropdownOnHover // Use the config.js value
31        : true // Use this if you are not using the config.js and want to set value directly from here
32    });
33    // Change parameter to true if you want scroll animation
34    window.Helpers.scrollToActive((animate = false));
35    window.Helpers.mainMenu = menu;
36  });
37
38  // Initialize menu togglers and bind click on each
39  let menuToggler = document.querySelectorAll('.layout-menu-toggle');
40  menuToggler.forEach(item => {
41    item.addEventListener('click', event => {
42      event.preventDefault();
43      window.Helpers.toggleCollapsed();
44      // Enable menu state with local storage support if enableMenuLocalStorage = true from config.js
45      if (config.enableMenuLocalStorage && !window.Helpers.isSmallScreen()) {
46        try {
47          localStorage.setItem(
48            'templateCustomizer-' + templateName + '--LayoutCollapsed',
49            String(window.Helpers.isCollapsed())
50          );
51        } catch (e) {}
52      }
53    });
54  });
55
56  // Menu swipe gesture
57
58  // Detect swipe gesture on the target element and call swipe In
59  window.Helpers.swipeIn('.drag-target', function (e) {
60    window.Helpers.setCollapsed(false);
61  });
62
63  // Detect swipe gesture on the target element and call swipe Out
64  window.Helpers.swipeOut('#layout-menu', function (e) {
65    if (window.Helpers.isSmallScreen()) window.Helpers.setCollapsed(true);
66  });
67
68  // Display in main menu when menu scrolls
69  let menuInnerContainer = document.getElementsByClassName('menu-inner'),
70    menuInnerShadow = document.getElementsByClassName('menu-inner-shadow')[0];
71  if (menuInnerContainer.length > 0 && menuInnerShadow) {
72    menuInnerContainer[0].addEventListener('ps-scroll-y', function () {
73      if (this.querySelector('.ps__thumb-y').offsetTop) {
74        menuInnerShadow.style.display = 'block';
75      } else {
76        menuInnerShadow.style.display = 'none';
77      }
78    });
79  }
80
81  // Style Switcher (Light/Dark Mode)
82  //---------------------------------
83
84  let styleSwitcherToggleEl = document.querySelector('.style-switcher-toggle');
85  if (window.templateCustomizer) {
86    // setStyle light/dark on click of styleSwitcherToggleEl
87    if (styleSwitcherToggleEl) {
88      styleSwitcherToggleEl.addEventListener('click', function () {
89        if (window.Helpers.isLightStyle()) {
90          window.templateCustomizer.setStyle('dark');
91        } else {
92          window.templateCustomizer.setStyle('light');
93        }
94      });
95    }
96    // Update style switcher icon and tooltip based on current style
97    if (window.Helpers.isLightStyle()) {
98      if (styleSwitcherToggleEl) {
99        styleSwitcherToggleEl.querySelector('i').classList.add('bx-moon');
100        new bootstrap.Tooltip(styleSwitcherToggleEl, {
101          title: 'Dark mode',
102          fallbackPlacements: ['bottom']
103        });
104      }
105      switchImage('light');
106    } else {
107      if (styleSwitcherToggleEl) {
108        styleSwitcherToggleEl.querySelector('i').classList.add('bx-sun');
109        new bootstrap.Tooltip(styleSwitcherToggleEl, {
110          title: 'Light mode',
111          fallbackPlacements: ['bottom']
112        });
113      }
114      switchImage('dark');
115    }
116  }
117
118  // Update light/dark image based on current style
119  function switchImage(style) {
120    const switchImagesList = [].slice.call(document.querySelectorAll('[data-app-' + style + '-img]'));
121    switchImagesList.map(function (imageEl) {
122      const setImage = imageEl.getAttribute('data-app-' + style + '-img');
123      imageEl.src = assetsPath + 'img/' + setImage; // Using window.assetsPath to get the exact relative path
124    });
125  }
126
127  // Navbar Scroll class
128  //---------------------
129  function scrollTopFn() {
130    if (document.getElementById('layout-navbar')) {
131      if (document.body.scrollTop > 10 || document.documentElement.scrollTop > 10) {
132        document.getElementById('layout-navbar').classList.add('navbar-elevated');
133      } else {
134        document.getElementById('layout-navbar').classList.remove('navbar-elevated');
135      }
136    }
137  }
138  window.onscroll = function () {
139    scrollTopFn();
140  };
141  // Internationalization (Language Dropdown)
142  // ---------------------------------------
143
144  if (typeof i18next !== 'undefined' && typeof i18NextHttpBackend !== 'undefined') {
145    i18next
146      .use(i18NextHttpBackend)
147      .init({
148        lng: 'en',
149        debug: false,
150        fallbackLng: 'en',
151        backend: {
152          loadPath: assetsPath + 'json/locales/{{lng}}.json'
153        },
154        returnObjects: true
155      })
156      .then(function (t) {
157        localize();
158      });
159  }
160
161  let languageDropdown = document.getElementsByClassName('dropdown-language');
162
163  if (languageDropdown.length) {
164    let dropdownItems = languageDropdown[0].querySelectorAll('.dropdown-item');
165
166    for (let i = 0; i < dropdownItems.length; i++) {
167      dropdownItems[i].addEventListener('click', function () {
168        let currentLanguage = this.getAttribute('data-language'),
169          selectedLangFlag = this.querySelector('.fi').getAttribute('class'),
170          startsWith = 'fs-',
171          classes = selectedLangFlag.split(' ').filter(function (v) {
172            return v.lastIndexOf(startsWith, 0) !== 0;
173          });
174        selectedLangFlag = classes.join(' ').trim() + ' fs-3';
175
176        for (let sibling of this.parentNode.children) {
177          sibling.classList.remove('selected');
178        }
179        this.classList.add('selected');
180
181        languageDropdown[0].querySelector('.dropdown-toggle .fi').className = selectedLangFlag;
182
183        i18next.changeLanguage(currentLanguage, (err, t) => {
184          if (err) return console.log('something went wrong loading', err);
185          localize();
186        });
187      });
188    }
189  }
190
191  function localize() {
192    let i18nList = document.querySelectorAll('[data-i18n]');
193    // Set the current language in dd
194    let currentLanguageEle = document.querySelector('.dropdown-item[data-language="' + i18next.language + '"]');
195
196    if (currentLanguageEle) {
197      currentLanguageEle.click();
198    }
199
200    i18nList.forEach(function (item) {
201      item.innerHTML = i18next.t(item.dataset.i18n);
202    });
203  }
204
205  // Notification
206  // ------------
207  const notificationMarkAsReadAll = document.querySelector('.dropdown-notifications-all');
208  const notificationMarkAsReadList = document.querySelectorAll('.dropdown-notifications-read');
209
210  // Notification: Mark as all as read
211  if (notificationMarkAsReadAll) {
212    notificationMarkAsReadAll.addEventListener('click', event => {
213      notificationMarkAsReadList.forEach(item => {
214        item.closest('.dropdown-notifications-item').classList.add('marked-as-read');
215      });
216    });
217  }
218  // Notification: Mark as read/unread onclick of dot
219  if (notificationMarkAsReadList) {
220    notificationMarkAsReadList.forEach(item => {
221      item.addEventListener('click', event => {
222        item.closest('.dropdown-notifications-item').classList.toggle('marked-as-read');
223      });
224    });
225  }
226
227  // Notification: Mark as read/unread onclick of dot
228  const notificationArchiveMessageList = document.querySelectorAll('.dropdown-notifications-archive');
229  notificationArchiveMessageList.forEach(item => {
230    item.addEventListener('click', event => {
231      item.closest('.dropdown-notifications-item').remove();
232    });
233  });
234
235  // Init helpers & misc
236  // --------------------
237
238  // Init BS Tooltip
239  const tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'));
240  tooltipTriggerList.map(function (tooltipTriggerEl) {
241    return new bootstrap.Tooltip(tooltipTriggerEl);
242  });
243
244  // Accordion active class
245  const accordionActiveFunction = function (e) {
246    if (e.type == 'show.bs.collapse' || e.type == 'show.bs.collapse') {
247      e.target.closest('.accordion-item').classList.add('active');
248    } else {
249      e.target.closest('.accordion-item').classList.remove('active');
250    }
251  };
252
253  const accordionTriggerList = [].slice.call(document.querySelectorAll('.accordion'));
254  const accordionList = accordionTriggerList.map(function (accordionTriggerEl) {
255    accordionTriggerEl.addEventListener('show.bs.collapse', accordionActiveFunction);
256    accordionTriggerEl.addEventListener('hide.bs.collapse', accordionActiveFunction);
257  });
258
259  // If layout is RTL add .dropdown-menu-end class to .dropdown-menu
260  if (isRtl) {
261    Helpers._addClass('dropdown-menu-end', document.querySelectorAll('#layout-navbar .dropdown-menu'));
262  }
263
264  // Auto update layout based on screen size
265  window.Helpers.setAutoUpdate(true);
266
267  // Toggle Password Visibility
268  window.Helpers.initPasswordToggle();
269
270  // Speech To Text
271  window.Helpers.initSpeechToText();
272
273  // Init PerfectScrollbar in Navbar Dropdown (i.e notification)
274  window.Helpers.initNavbarDropdownScrollbar();
275
276  // On window resize listener
277  // -------------------------
278  window.addEventListener(
279    'resize',
280    function (event) {
281      // Hide open search input and set value blank
282      if (window.innerWidth >= window.Helpers.LAYOUT_BREAKPOINT) {
283        if (document.querySelector('.search-input-wrapper')) {
284          document.querySelector('.search-input-wrapper').classList.add('d-none');
285          document.querySelector('.search-input').value = '';
286        }
287      }
288      // Horizontal Layout : Update menu based on window size
289      let horizontalMenuTemplate = document.querySelector("[data-template^='horizontal-menu']");
290      if (horizontalMenuTemplate) {
291        setTimeout(function () {
292          if (window.innerWidth < window.Helpers.LAYOUT_BREAKPOINT) {
293            if (document.getElementById('layout-menu')) {
294              if (document.getElementById('layout-menu').classList.contains('menu-horizontal')) {
295                menu.switchMenu('vertical');
296              }
297            }
298          } else {
299            if (document.getElementById('layout-menu')) {
300              if (document.getElementById('layout-menu').classList.contains('menu-vertical')) {
301                menu.switchMenu('horizontal');
302              }
303            }
304          }
305        }, 100);
306      }
307    },
308    true
309  );
310
311  // Manage menu expanded/collapsed with templateCustomizer & local storage
312  //------------------------------------------------------------------
313
314  // If current layout is horizontal OR current window screen is small (overlay menu) than return from here
315  if (isHorizontalLayout || window.Helpers.isSmallScreen()) {
316    return;
317  }
318
319  // If current layout is vertical and current window screen is > small
320
321  // Auto update menu collapsed/expanded based on the themeConfig
322  if (typeof TemplateCustomizer !== 'undefined') {
323    if (window.templateCustomizer.settings.defaultMenuCollapsed) {
324      window.Helpers.setCollapsed(true, false);
325    }
326  }
327
328  // Manage menu expanded/collapsed state with local storage support If enableMenuLocalStorage = true in config.js
329  if (typeof config !== 'undefined') {
330    if (config.enableMenuLocalStorage) {
331      try {
332        if (
333          localStorage.getItem('templateCustomizer-' + templateName + '--LayoutCollapsed') !== null &&
334          localStorage.getItem('templateCustomizer-' + templateName + '--LayoutCollapsed') !== 'false'
335        )
336          window.Helpers.setCollapsed(
337            localStorage.getItem('templateCustomizer-' + templateName + '--LayoutCollapsed') === 'true',
338            false
339          );
340      } catch (e) {}
341    }
342  }
343})();
344
345// ! Removed following code if you do't wish to use jQuery. Remember that navbar search functionality will stop working on removal.
346if (typeof $ !== 'undefined') {
347  $(function () {
348    // ! TODO: Required to load after DOM is ready, did this now with jQuery ready.
349    window.Helpers.initSidebarToggle();
350    // Toggle Universal Sidebar
351
352    // Navbar Search with autosuggest (typeahead)
353    // ? You can remove the following JS if you don't want to use search functionality.
354    //----------------------------------------------------------------------------------
355
356    var searchToggler = $('.search-toggler'),
357      searchInputWrapper = $('.search-input-wrapper'),
358      searchInput = $('.search-input'),
359      contentBackdrop = $('.content-backdrop');
360
361    // Open search input on click of search icon
362    if (searchToggler.length) {
363      searchToggler.on('click', function () {
364        if (searchInputWrapper.length) {
365          searchInputWrapper.toggleClass('d-none');
366          searchInput.focus();
367        }
368      });
369    }
370    // Open search on 'CTRL+/'
371    $(document).on('keydown', function (event) {
372      let ctrlKey = event.ctrlKey,
373        slashKey = event.which === 191;
374
375      if (ctrlKey && slashKey) {
376        if (searchInputWrapper.length) {
377          searchInputWrapper.toggleClass('d-none');
378          searchInput.focus();
379        }
380      }
381    });
382    // Todo: Add container-xxl to twitter-typeahead
383    searchInput.on('focus', function () {
384      if (searchInputWrapper.hasClass('container-xxl')) {
385        searchInputWrapper.find('.twitter-typeahead').addClass('container-xxl');
386      }
387    });
388
389    if (searchInput.length) {
390      // Filter config
391      var filterConfig = function (data) {
392        return function findMatches(q, cb) {
393          let matches;
394          matches = [];
395          data.filter(function (i) {
396            if (i.name.toLowerCase().startsWith(q.toLowerCase())) {
397              matches.push(i);
398            } else if (
399              !i.name.toLowerCase().startsWith(q.toLowerCase()) &&
400              i.name.toLowerCase().includes(q.toLowerCase())
401            ) {
402              matches.push(i);
403              matches.sort(function (a, b) {
404                return b.name < a.name ? 1 : -1;
405              });
406            } else {
407              return [];
408            }
409          });
410          cb(matches);
411        };
412      };
413
414      // Search JSON
415      var searchJson = 'search-vertical.json'; // For vertical layout
416      if ($('#layout-menu').hasClass('menu-horizontal')) {
417        var searchJson = 'search-horizontal.json'; // For vertical layout
418      }
419      // Search API AJAX call
420      var searchData = $.ajax({
421        url: assetsPath + 'json/' + searchJson, //? Use your own search api instead
422        dataType: 'json',
423        async: false
424      }).responseJSON;
425      // Init typeahead on searchInput
426      searchInput.each(function () {
427        var $this = $(this);
428        searchInput
429          .typeahead(
430            {
431              hint: false,
432              classNames: {
433                menu: 'tt-menu navbar-search-suggestion',
434                cursor: 'active',
435                suggestion: 'suggestion d-flex justify-content-between px-3 py-2 w-100'
436              }
437            },
438            // ? Add/Update blocks as per need
439            // Pages
440            {
441              name: 'pages',
442              display: 'name',
443              limit: 5,
444              source: filterConfig(searchData.pages),
445              templates: {
446                header: '<h6 class="suggestions-header text-primary mb-0 mx-3 mt-3 pb-2">Pages</h6>',
447                suggestion: function ({ url, icon, name }) {
448                  return (
449                    '<a href="' +
450                    url +
451                    '">' +
452                    '<div>' +
453                    '<i class="bx ' +
454                    icon +
455                    ' me-2"></i>' +
456                    '<span class="align-middle">' +
457                    name +
458                    '</span>' +
459                    '</div>' +
460                    '</a>'
461                  );
462                },
463                notFound:
464                  '<div class="not-found px-3 py-2">' +
465                  '<h6 class="suggestions-header text-primary mb-2">Pages</h6>' +
466                  '<p class="py-2 mb-0"><i class="bx bx-error-circle bx-xs me-2"></i> No Results Found</p>' +
467                  '</div>'
468              }
469            },
470            // Files
471            {
472              name: 'files',
473              display: 'name',
474              limit: 4,
475              source: filterConfig(searchData.files),
476              templates: {
477                header: '<h6 class="suggestions-header text-primary mb-0 mx-3 mt-3 pb-2">Files</h6>',
478                suggestion: function ({ src, name, subtitle, meta }) {
479                  return (
480                    '<a href="javascript:;">' +
481                    '<div class="d-flex w-50">' +
482                    '<img class="me-3" src="' +
483                    assetsPath +
484                    src +
485                    '" alt="' +
486                    name +
487                    '" height="32">' +
488                    '<div class="w-75">' +
489                    '<h6 class="mb-0">' +
490                    name +
491                    '</h6>' +
492                    '<small class="text-muted">' +
493                    subtitle +
494                    '</small>' +
495                    '</div>' +
496                    '</div>' +
497                    '<small class="text-muted">' +
498                    meta +
499                    '</small>' +
500                    '</a>'
501                  );
502                },
503                notFound:
504                  '<div class="not-found px-3 py-2">' +
505                  '<h6 class="suggestions-header text-primary mb-2">Files</h6>' +
506                  '<p class="py-2 mb-0"><i class="bx bx-error-circle bx-xs me-2"></i> No Results Found</p>' +
507                  '</div>'
508              }
509            },
510            // Members
511            {
512              name: 'members',
513              display: 'name',
514              limit: 4,
515              source: filterConfig(searchData.members),
516              templates: {
517                header: '<h6 class="suggestions-header text-primary mb-0 mx-3 mt-3 pb-2">Members</h6>',
518                suggestion: function ({ name, src, subtitle }) {
519                  return (
520                    '<a href="app-user-view-account.html">' +
521                    '<div class="d-flex align-items-center">' +
522                    '<img class="rounded-circle me-3" src="' +
523                    assetsPath +
524                    src +
525                    '" alt="' +
526                    name +
527                    '" height="32">' +
528                    '<div class="user-info">' +
529                    '<h6 class="mb-0">' +
530                    name +
531                    '</h6>' +
532                    '<small class="text-muted">' +
533                    subtitle +
534                    '</small>' +
535                    '</div>' +
536                    '</div>' +
537                    '</a>'
538                  );
539                },
540                notFound:
541                  '<div class="not-found px-3 py-2">' +
542                  '<h6 class="suggestions-header text-primary mb-2">Members</h6>' +
543                  '<p class="py-2 mb-0"><i class="bx bx-error-circle bx-xs me-2"></i> No Results Found</p>' +
544                  '</div>'
545              }
546            }
547          )
548          //On typeahead result render.
549          .bind('typeahead:render', function () {
550            // Show content backdrop,
551            contentBackdrop.addClass('show').removeClass('fade');
552          })
553          // On typeahead select
554          .bind('typeahead:select', function (ev, suggestion) {
555            // Open selected page
556            if (suggestion.url) {
557              window.location = suggestion.url;
558            }
559          })
560          // On typeahead close
561          .bind('typeahead:close', function () {
562            // Clear search
563            searchInput.val('');
564            $this.typeahead('val', '');
565            // Hide search input wrapper
566            searchInputWrapper.addClass('d-none');
567            // Fade content backdrop
568            contentBackdrop.addClass('fade').removeClass('show');
569          });
570
571        // On searchInput keyup, Fade content backdrop if search input is blank
572        searchInput.on('keyup', function () {
573          if (searchInput.val() == '') {
574            contentBackdrop.addClass('fade').removeClass('show');
575          }
576        });
577      });
578
579      // Init PerfectScrollbar in search result
580      var psSearch;
581      $('.navbar-search-suggestion').each(function () {
582        psSearch = new PerfectScrollbar($(this)[0], {
583          wheelPropagation: false,
584          suppressScrollX: true
585        });
586      });
587
588      searchInput.on('keyup', function () {
589        psSearch.update();
590      });
591    }
592  });
593}

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.