PageSourceSearch

https://miamiarchdiocese.org/Library/js/AtimoComponents.js?v=4

js miamiarchdiocese.org collected 2026-10-02 10:36:11 UTC 28,884 bytes, 901 lines download raw bytes

1/*
2INDEX
3	01) PAGE LAYOUT & COMPONENTS
4		- NAVIGATION BUTTONS
5		- MAIN MENU
6		- VERTICAL MENU
7		- MODAL WINDOW
8		- INFO BOX
9		- SEARCH CHURCH/SCHOOL
10		- FOOTER SECTION
11		- SUBSCRIBE MAILING LIST
12                - SCROLL BAR
13	03) MISCELLANEOUS
14	04) RESIZE CAPTIONS
15    05) TOGGLE BTN
16*/
17/*-----------------------------------------------------------  PAGE LAYOUT & COMPONENTS  -------*/
18
19$(function () {
20  var window_width = $(window).width(),
21    str = location.href.toLowerCase();
22
23  section_navigation(str);
24
25  /*---  INFO BOX -----------------*/
26  if (window_width < 729) {
27    $(".info_box h1").toggle(
28      function () {
29        $(this).css("backgroundPosition", "right -422px");
30        $(this).next(".info").show("slow");
31      },
32      function () {
33        $(this).css("backgroundPosition", "right -363px");
34        $(this).next(".info").hide("slow");
35      }
36    );
37  }
38
39  /*---  SEARCH CHURCH/SCHOOL ------*/
40  var last_search_box = "";
41  var search_boxes = $("#search_boxes");
42  $(".search_box").click(function () {
43    $(search_boxes).html('<div class="uploading"></div>');
44    $(search_boxes).load(this.href, function () {
45      $('select[name="op"]').on("change", function (e) {
46        this.form.submit();
47      });
48    });
49    return false;
50  });
51
52  /*----- Hide the search box -----*/
53  $("#search_boxes").on("click", "#search_boxes_close", function () {
54    $("#search_boxes").empty();
55  });
56
57  /*---- Home page Church/School Dropdown change ---*/
58  $('select[name="op"]').on("change", function (e) {
59    this.form.submit();
60  });
61
62  //Call SHOW/HIDE INFO functionality on without ajax load
63  show_hide_info();
64
65  $(".clergy_relationships").click(function (e) {
66    if ($(this).css("top") == "155px") {
67      $(this).animate({ top: "284" }, 400);
68    } else {
69      $(this).animate({ top: "155" }, 400);
70    }
71  });
72
73  /*---  RESIZE CAPTIONS -----------*/
74  resize_captions();
75
76  var detail_width = 500;
77  var detail_height = 500;
78  var inline = $("#inline");
79
80  function loadDetails(href) {
81    $("#details")
82      .css({
83        width: detail_width + "px",
84        height: detail_height + "px",
85      })
86      .load(href + " #MW", function () {
87        inline.trigger("click");
88      });
89  }
90
91  $("a.mwindow, a.find_entities").click(function (e) {
92    var windowWidth = $(window).width();
93    detail_width = windowWidth <= 750 ? 300 : 500;
94    detail_height = windowWidth <= 750 ? 635 : 500;
95    e.preventDefault();
96    loadDetails(this.href);
97  });
98}); // End of document ready
99
100$(document).ajaxComplete(function () {
101  section_navigation(location.href.toLowerCase());
102  // handler for opening popups
103  $(".js-popup").on("click", open_window);
104  $("#js-relationship_type").on("change", update_visible);
105  $("#js-relationship_entity").on("change", auto_fill_org);
106  bind_default_form();
107});
108
109/*---------------------------------------------------  GENERIC SHOW/HIDE INFO ANCHOR TAG CLICK ------*/
110function show_hide_info() {
111  $(".js-reveal_description").click(function (e) {
112    // this will keep the reference to what was clicked
113    var _this = $(this);
114    $(_this)
115      .siblings(".js-description")
116      .slideToggle("slow", function () {
117        // now this is pointing to the description
118        if ($(this).is(":visible")) {
119          $(_this).text("Hide details").addClass("active");
120        } else {
121          $(_this).text("Show details").removeClass("active");
122        }
123      });
124    e.preventDefault();
125  });
126}
127
128/*-----------------------------------------------------------  MISCELLANEOUS  ------------------*/
129function section_navigation(str) {
130  $(".section_navigation a, .section_navigation_ministry a").each(function () {
131    if (str.indexOf(this.href.toLowerCase()) > -1) {
132      if ($(this).hasClass("selected")) {
133        return false;
134      } else {
135        $(this).addClass("selected");
136      }
137    }
138  });
139}
140
141$(document).ready(function () {
142  var selectedAnchor = $(".section_navigation:first a.selected");
143  if (selectedAnchor.length > 0) {
144    var selectedText = selectedAnchor.text();
145    var regex = /([A-Z][a-z]+ [A-Z][a-z]+)(?=[A-Z])/;
146    var result = regex.exec(selectedText);
147    var textRender = selectedText;
148
149    if (result !== null) {
150      textRender = result[1];
151    }
152
153    var h3Element = $("<h3>").addClass("navigation_title").text(textRender);
154    $(".section_navigation:first").after(h3Element);
155  }
156});
157
158// Org.name load when onchange of church or school selection function
159function common_event_function() {
160  $("#js-eventwhere").on("change", function (e) {
161    $("#js-auto_fill_location").load(
162      "atimo_s/ajax/account/organization.php?id=" +
163        $("option:selected", this).attr("data-id")
164    );
165  });
166}
167
168function auto_fill_org() {
169  //console.log('defined');
170  var id = $(this, "option").val();
171  if (id != "") {
172    $("#organization_location").load(
173      "atimo_s/ajax/account/my_location.php?id=" + id
174    );
175  } else {
176    $("#organization_location").html("");
177  }
178}
179// load events for a ministry/department
180function load_events(op, container) {
181  if (typeof container === "undefined") {
182    container = "#ministry_events";
183  }
184
185  var text = $("#plus").html();
186
187  $(container).load(
188    "atimo_s/ajax/show_events/events_by_ministry.php?ministry_main_op=" + op,
189    function () {
190      show_hide_info();
191      if (typeof buildBookmarks === "function") {
192        buildBookmarks(".event", ".event h3", "#page_title");
193      }
194      $(".box_index h3").click(function () {
195        $(".page_index").slideToggle();
196        $(".page_index").toggleClass("index_hide");
197        if ($(".page_index:not(.index_hide)")) {
198          $(".box_index h3").removeClass("closed");
199          $(".box_index h3").addClass("open");
200          $("#plus").text("-");
201        }
202        if ($(".page_index").hasClass("index_hide")) {
203          $(".box_index h3").removeClass("open");
204          $(".box_index h3").addClass("closed");
205          $("#plus").text("+");
206        }
207      });
208    }
209  );
210}
211
212// introduce .trim() for browsers that do not support
213if (!String.prototype.trim) {
214  String.prototype.trim = function () {
215    return this.replace(/^\s+|\s+$/g, "");
216  };
217}
218// this changes the options in the select menu
219function update_visible() {
220  var value = this.value;
221  var options = $("#js-" + value);
222  var entity = $("#js-relationship_entity");
223  var org_id = $("#organization_location");
224
225  entity.prop("disabled", false);
226  if (value == "") {
227    $(entity).html(
228      '<option value="">First, select an option above...</option>'
229    );
230    org_id.html("");
231  } else if (value == "other") {
232    entity.html("").prop("disabled", true);
233    org_id.load("atimo_s/ajax/account/my_location.php?id=0");
234  } else {
235    $(entity).html($(options).html());
236  }
237}
238
239//Scroll bar
240function applyCustomScrollbarStyle() {
241  const vmenu = document.querySelector(".vmenu01");
242  vmenu.classList.add("scrollbar-hover");
243}
244
245function resetCustomScrollbarStyle() {
246  const vmenu = document.querySelector(".vmenu01");
247  vmenu.classList.remove("scrollbar-hover");
248}
249
250$(document).ready(function () {
251  var slideFrame = $(".slide_frame");
252  var rsNav = $(".rsNav.rsThumbs.rsThumbsHor");
253  var rsGCaption = $(".rsGCaption");
254
255  rsNav.detach();
256  rsGCaption.detach();
257
258  slideFrame.append(rsGCaption);
259  slideFrame.append(rsNav);
260});
261
262/**
263 * HOW DO I USE THIS THING?!
264 * 1) wrap the content you want to tabify in a <div> with a class of js-tabs
265 * 2) wrap the things to be tabbed in <div>s
266 * 3) add an anchor inside each div with the following information:
267 * 		- class = js-group-button
268 *		- data-name = [name of the tab for the section navigatin that will be created]
269 * 4) add toggle_tabs(); to the document
270 * 5) ???
271 * 6) profit
272 */
273function toggle_tabs() {
274  // prevent multiple navs from being created if the
275  // tabs are created after an ajax call
276  if ($(".js-tab-manager").length === 1) {
277    return false;
278  }
279
280  // pick up the tabs, anchors and setup the nav html
281  var group = $(".js-tabs");
282  var anchors = $(".js-group-button");
283  var nav = '<div class="section_navigation js-tab-manager">';
284
285  // if there are any anchors
286  if (anchors.length > 0) {
287    // start i at 0 as the elements will be 0 indexed
288    var i = 0;
289    // we are going to hide all the children of the group
290    // with the exception of the first child
291    $(group).children("div:not(:first-child)").addClass("hide");
292
293    // iterate over each anchor
294    $(anchors).each(function () {
295      // pick up the data-name of each anchor, this will be used for the buttons
296      var name = $(this).attr("data-name");
297
298      // if we don't have a name, just set it to the numerical index
299      if (typeof name === "undefined") {
300        name = "Tab " + i;
301      }
302
303      // generate a button with the name and, most importantly,
304      // the numerical index of each anchor
305      nav += '<a data-tab-index="' + i + '">' + name + "</a>";
306
307      // increment
308      i++;
309    });
310
311    // close the div
312    nav += "</div>";
313
314    // add the div just below the opening div of the group, and add selected to the first child
315    $(group)
316      .prepend(nav)
317      .find(".js-tab-manager")
318      .children()
319      .filter(":first-child")
320      .addClass("selected");
321
322    // add the on click handler to each of the buttons
323    $(".js-tab-manager")
324      .children()
325      .on("click", function () {
326        // get the index and convert it to an int via Math.floor()
327        var index = Math.floor($(this).attr("data-tab-index"));
328        // grab all the direct children of the parent and exclude the tab-manager
329        var children = $(group).children().not(".js-tab-manager");
330
331        // "this" is of course what was clicked. Since this is independent
332        // of href, we have to add and remove "selected" manually
333        $(this).addClass("selected").siblings().removeClass("selected");
334
335        // find all the childen according to the filter above and hide them
336        $(children).addClass("hide");
337        // now pick up the desired div via the $.eq() method
338        $(children).eq(index).removeClass("hide");
339      });
340  }
341}
342
343function open_window(e) {
344  var title = $(this).attr("data-title");
345  var width = $(this).attr("data-width");
346  var height = $(this).attr("data-height");
347
348  var windowObjectReference = null; // global variable
349  // if the pointer to the window object in memory does not exist or if such pointer exists but the window was closed
350  if (windowObjectReference == null || windowObjectReference.closed) {
351    // then create it. The new window will be created and will be brought on top of any other window.
352    windowObjectReference = window.open(
353      this.href,
354      title,
355      "resizable, scrollbars, status, width=" + width + ", height=" + height
356    );
357  } else {
358    // else the window reference must exist and the window is not closed; therefore, we can bring it back on top of any other
359    // window with the focus() method. There would be no need to re-create the window or to reload the referenced resource.
360    windowObjectReference.focus();
361  }
362  e.preventDefault();
363}
364
365/*-----------------------------------------------------------  RESIZE CAPTIONS  ----------------*/
366function resize_captions() {
367  $(".js-caption img").each(function () {
368    var window_width = $(window).width();
369    var parent = $(this).parent();
370    var width = $(this).attr("data-width");
371
372    console.log(window_width);
373
374    if (
375      window_width > 500 &&
376      (parent.hasClass("pic_articleL") || parent.hasClass("pic_articleR"))
377    ) {
378      parent.css("width", width);
379    }
380
381    if (window_width > 830 && parent.hasClass("pic_articleC")) {
382      parent.css("width", width);
383    }
384  });
385}
386
387/*  TOGGLE BTN ---------------------------------------------------------------------------------*/
388$(document).on("click", ".js-toggle-btn", function (event) {
389  $(this).find(".js-toggle-content").toggle();
390});
391
392/*-----------------------------------------------------------  Google recaptcha  ----------------*/
393
394$(document).on("ajaxComplete", function () {
395  $("form .atimo-recaptcha-response")
396    .closest("form")
397    .find(":submit")
398    .addClass("g-recaptcha");
399});
400
401$(function () {
402  $("form .atimo-recaptcha-response")
403    .closest("form")
404    .find(":submit")
405    .addClass("g-recaptcha");
406});
407
408$(document).on("click", "form .g-recaptcha:submit", function (event) {
409  event.preventDefault();
410  let thisForm = $(this).closest("form");
411
412  let currentTime = new Date();
413  let recaptcha_timeout = thisForm.find('input[name="sys_recaptcha_timeout"]')
414    .length
415    ? new Date(thisForm.find('input[name="sys_recaptcha_timeout"]').val())
416    : "";
417
418  if (recaptcha_timeout == "" || currentTime > recaptcha_timeout) {
419    grecaptcha
420      .execute("6LdtcPMUAAAAAIdy60B4mNcrgjF98b-oX94Dglnm", {
421        action: "homepage",
422      })
423      .then(function (token) {
424        let new_recaptcha_timeout = new Date();
425        new_recaptcha_timeout.setMinutes(
426          new_recaptcha_timeout.getMinutes() + 2
427        );
428        if (thisForm.find('input[name="sys_recaptcha_timeout"]').length) {
429          thisForm
430            .find('input[name="sys_recaptcha_timeout"]')
431            .val(new_recaptcha_timeout);
432        } else {
433          thisForm.prepend(
434            '<input name="sys_recaptcha_timeout" type="hidden" value="' +
435              new_recaptcha_timeout +
436              '">'
437          );
438        }
439        thisForm.find(".atimo-recaptcha-response").val(token);
440        thisForm.submit();
441      });
442  } else {
443    thisForm.submit();
444  }
445});
446
447/* SCTN NAVIG COLAPPSE -------------------------------------------------------------------------*/
448$(document).ready(function () {
449  const sectionNav = $(".section_navigation").addClass("hide_mobile");
450  const selectNav = $("<div>").attr({
451    id: "section_div",
452    class: "hide_desktop",
453  });
454  const listNav = $("<select>").attr({ id: "section_select", name: "itens" });
455
456  sectionNav.find("a").each(function () {
457    const hrefValue = $(this).attr("href");
458    const optionValue = hrefValue.split("?op=")[1]; // Obtém o valor após "?op="
459    const optionText = $(this).text();
460    const option = $("<option>").val(optionValue).text(optionText);
461    listNav.append(option);
462  });
463
464  selectNav.append(listNav);
465  sectionNav.after(selectNav);
466
467  listNav.change(function () {
468    const indexOfOp = window.location.href.indexOf("?op=");
469    if (indexOfOp !== -1) {
470      const newUrl =
471        window.location.href.substring(0, indexOfOp + 4) + $(this).val();
472      window.location.replace(newUrl);
473    }
474  });
475});
476
477// TEMPORARIO - Matheus Ramos -- TROCA AQUI CARLOS
478$(document).ready(function () {
479  var currentPageUrl = window.location.href;
480  $("#section_select option").each(function () {
481    var optionValue = $(this).val();
482    if (currentPageUrl.indexOf(optionValue) !== -1) {
483      $(this).prop("selected", true);
484      return false;
485    }
486  });
487});
488
489// SUA FUNÇÂO TEM Q ESTAR AQUI TAMBÈM. SE TIVER EM OUTRO LUGAR TEM Q RETIRAR
490
491function ci_open() {
492  var flexDiv = $("#contact_info div.flex");
493  var button = $(".button_contact");
494  if (flexDiv.is(":visible")) {
495    flexDiv.slideUp(1000, function () {
496      flexDiv.css("display", "none");
497      button.find("i").removeClass("fa-chevron-up").addClass("fa-chevron-down");
498    });
499  } else {
500    flexDiv.css("display", "flex").css("height", "0");
501    var targetHeight = flexDiv.prop("scrollHeight");
502    flexDiv.animate({ height: targetHeight }, 1000, function () {
503      flexDiv.css("height", "auto");
504      button.find("i").removeClass("fa-chevron-down").addClass("fa-chevron-up");
505    });
506  }
507}
508
509// ESSA FUNÇÃO ALEATORIZA O A POSIÇÃO DO BACKGROUND DE WAVE NAS MÉDIAS 1500px E SUPERIOR
510
511document.addEventListener("DOMContentLoaded", function () {
512  if (window.matchMedia("(min-width: 1500px)").matches) {
513    var banner = document.getElementById("banner_top_img");
514
515    if (banner) {
516      var randomX = getRandomInt(0, 5);
517      var randomY = getRandomInt(0, 2);
518      var rotator = getRandomInt(0, 1);
519      var backgroundDiv = document.createElement("div");
520      backgroundDiv.className = "background";
521      backgroundDiv.style.backgroundPosition = randomX + "%" + randomY + "%";
522      backgroundDiv.style.transform =
523        "rotate(" +
524        (rotator == 0 ? getRandomInt(175, 180) : getRandomInt(0, 15)) +
525        "deg) scaleX(-1)";
526      banner.appendChild(backgroundDiv);
527    }
528  }
529});
530
531function getRandomInt(min, max) {
532  return Math.floor(Math.random() * (max - min + 1)) + min;
533}
534
535  /*----- SECTION NAVIGATION SCHOOLS AND CHURCHES -----*/ 
536
537$(document).ready(function () {
538  const urlParams = new URLSearchParams(window.location.search);
539  const opParam = urlParams.get("op");
540
541  if (
542    opParam &&
543    (opParam.startsWith("Church") || opParam.startsWith("School"))
544  ) {
545    const urlSuffix = opParam.split("_").pop();
546
547    $(".section_navigation a").each(function () {
548      const href = $(this).attr("href");
549      const linkSuffix = href.split("_").pop();
550      if (urlSuffix === linkSuffix) {
551        $(this).addClass("selected");
552      }
553    });
554  }
555});
556
557
558/* TABS   --------------------------------------------------------*/
559let tabsInitialized = false;
560
561function initTabs(limit = 100) {
562	if (tabsInitialized) return;
563	let countTabs = 0;
564	let principalLang;
565	tabsInitialized = true;
566
567	$('.tabs').each(function () {
568		const tabs = $(this);
569		const dataType = tabs.data('type') || 'default';
570		const tabTitlesContainer = $('<div class="tab-titles"></div>').prependTo(tabs);
571
572		tabs.find('.tab').each(function (index) {
573			countTabs++;
574			const tab = $(this);
575			const title = tab.data('title');
576			const id = tab.data('id');
577
578			if (!principalLang) {
579				principalLang = title;
580			}
581
582			const tabTitleElement = $(`<div class="tab-title" data-title="${title}">${title}</div>`);
583
584			tabTitlesContainer.append(tabTitleElement);
585			if (dataType === 'multilingualTabs') {
586				const removeButton = $(`<div class="remove_button" data-id="${id}" data-title="${title}"><i class="fas fa-trash-alt"></i></div>`);
587				tabTitlesContainer.append(removeButton);
588
589				removeButton.on('click', function (e) {
590					if (principalLang == $(this).data('title')) {
591						alert('You cannot delete the primary language');
592					} else {
593						removeTab(tabTitleElement, dataType, tabs, limit, countTabs, $(this).data('id'));
594					}
595				});
596			}
597
598			tab.addClass('tab-content').hide();
599
600			if (index === 0) {
601				tabTitleElement.addClass('active');
602				tab.addClass('active').show();
603			}
604
605			tabTitleElement.on('click', function () {
606				switch (dataType) {
607					case 'stepByStep':
608						if (tabTitleElement.hasClass('disabled')) {
609							return;
610						}
611						break;
612				}
613
614				tabs.find('.tab-title').removeClass('active');
615				tabs.find('.tab').removeClass('active').hide();
616
617				tabTitleElement.addClass('active');
618				tab.addClass('active').show();
619
620				updateTabState(tabs, dataType, limit, countTabs);
621			});
622
623			tab.find('.subtabs').each(function () {
624				initSubTabs($(this));
625			});
626		});
627
628		// Multilingual tabs
629		if (dataType === 'multilingualTabs') {
630			const addButton = $('<div class="tab-title add-tab">+</div>');
631			tabTitlesContainer.append(addButton);
632
633			addButton.on('click', function () {
634				addTab(tabs, tabTitlesContainer, dataType, 'New', limit, countTabs);
635			});
636		}
637
638		updateTabState(tabs, dataType, limit, countTabs);
639	});
640
641	$('form').on('input change', function () {
642		const form = $(this);
643		let allFilled = true;
644
645		form.find('.js-required').each(function () {
646			if (!$(this).val()) {
647				allFilled = false;
648				return false;
649			}
650		});
651
652		form.find('input[type="submit"]').prop('disabled', !allFilled);
653
654		form.find('.tabs').each(function () {
655			const tabs = $(this);
656			const dataType = tabs.data('type') || 'default';
657			updateTabState(tabs, dataType, limit, countTabs);
658		});
659	});
660}
661
662/*-----------------------------------------------------------  SEARCHABLE COMBOBOX  -------------*/
663/* Combobox pesquisavel que substitui <select> grande. Markup gerado por
664   render_combobox() (global_myaccount.php): <input class="js-combobox" list=..
665   data-target=..> + <datalist> + <input type="hidden">.
666   Handlers delegados no document = sobrevivem as trocas de conteudo do library.js
667   (innerHTML nao re-executa <script>). */
668(function () {
669  function syncCombo(box) {
670    var dl  = document.getElementById(box.getAttribute('list')),
671        hid = document.getElementById(box.getAttribute('data-target'));
672    if (!hid) { return; }
673    var v = (box.value || '').trim(), id = '';
674    if (v !== '' && dl) {                       // campo vazio = sem selecao
675      for (var i = 0; i < dl.options.length; i++) {
676        if (dl.options[i].value.trim() !== '' && dl.options[i].value === v) {
677          id = dl.options[i].getAttribute('data-id'); break; // ignora option vazio
678        }
679      }
680    }
681    hid.value = id; // vazio se campo vazio OU nome nao casa exatamente com a lista
682  }
683
684  document.addEventListener('input', function (e) {
685    if (e.target && e.target.classList && e.target.classList.contains('js-combobox')) { syncCombo(e.target); }
686  });
687  document.addEventListener('change', function (e) {
688    if (e.target && e.target.classList && e.target.classList.contains('js-combobox')) { syncCombo(e.target); }
689  });
690
691  // No clique do Search/Submit (fase de captura = antes do library.js serializar):
692  // re-sincroniza e valida obrigatorio (data-required="1").
693  document.addEventListener('click', function (e) {
694    var t = e.target;
695    if (!(t && t.tagName === 'INPUT' && t.type === 'submit' && t.form)) { return; }
696    var boxes = t.form.querySelectorAll('.js-combobox');
697    for (var i = 0; i < boxes.length; i++) {
698      syncCombo(boxes[i]);
699      if (boxes[i].getAttribute('data-required') === '1') {
700        var hid = document.getElementById(boxes[i].getAttribute('data-target'));
701        if (hid && hid.value === '') {
702          e.preventDefault(); e.stopPropagation();
703          alert('Please select a valid option from the list.');
704          boxes[i].focus();
705          return;
706        }
707      }
708    }
709  }, true);
710})();
711
712function initSubTabs(subTabs) {
713	if (subTabs.find('.subTab-titles').length === 0) {
714		const subTabTitlesContainer = $('<div class="subTab-titles"></div>').prependTo(subTabs);
715
716		subTabs.find('.subtab').each(function (index) {
717			const subTab = $(this);
718			const subTabTitle = subTab.data('title');
719			const subTabTitleElement = $(`<div class="subTab-title">${subTabTitle}</div>`);
720
721			subTabTitlesContainer.append(subTabTitleElement);
722			subTab.addClass('subTab-content').hide();
723
724			if (index === 0) {
725				subTabTitleElement.addClass('active');
726				subTab.addClass('active').show();
727			}
728
729			subTabTitleElement.on('click', function () {
730				subTabs.find('.subTab-title').removeClass('active');
731				subTabs.find('.subtab').removeClass('active').hide();
732
733				subTabTitleElement.addClass('active');
734				subTab.addClass('active').show();
735			});
736		});
737	}
738}
739
740function updateTabState(tabs, dataType, limit, countTabs) {
741	if (dataType === 'stepByStep') {
742		let validUpTo = -1;
743		let isPreviousValid = true;
744
745		tabs.find('.tab').each(function (index) {
746			if (isPreviousValid && validateTab($(this))) {
747				validUpTo = index;
748			} else {
749				isPreviousValid = false;
750			}
751		});
752
753		tabs.find('.tab-title').each(function (index) {
754			const tabTitle = $(this);
755			if (index <= validUpTo + 1) {
756				tabTitle.removeClass('disabled');
757			} else {
758				tabTitle.addClass('disabled');
759			}
760
761			if (index <= validUpTo) {
762				tabTitle.addClass('filled');
763			} else {
764				tabTitle.removeClass('filled');
765			}
766		});
767	}
768
769	if (countTabs >= limit) {
770		tabs.find('.add-tab').remove();
771	}
772}
773
774function validateTab(tab) {
775	let isValid = true;
776	tab.find('.js-required').each(function () {
777		if (!$(this).val()) {
778			isValid = false;
779			return false;
780		}
781	});
782	return isValid;
783}
784
785function selectActiveTab(dataTitle) {
786  $('.tabs').each(function () {
787      const tabs = $(this);
788      let found = false;
789
790      tabs.find('.tab').each(function () {
791          const tab = $(this);
792          const tabTitle = tab.data('title');
793          
794          if (tabTitle === dataTitle) {
795              tabs.find('.tab-title').removeClass('active');
796              tabs.find('.tab').removeClass('active').hide();
797
798              tab.show().addClass('active');
799              tabs.find(`.tab-title[data-title="${tabTitle}"]`).addClass('active');
800
801              found = true;
802              return false; 
803          }
804      });
805
806      if (!found) {
807          console.log(`Aba com o título ${dataTitle} não foi encontrada.`);
808      }
809  });
810}
811// 
812
813
814/*------------------------------------------------------------------------------
815  LOADING INDICATOR — busca por palavra-chave + troca de página (paginação)
816  --------------------------------------------------------------------------
817  A busca (form) e os links de paginação (class="js-ajax") sao carregados pelo
818  library.js via AJAX. Aqui ligamos um overlay aos eventos globais do jQuery,
819  filtrando SO as requisicoes para keyword_search/search.php — assim nao afeta
820  nenhum outro AJAX do site.
821------------------------------------------------------------------------------*/
822(function () {
823  // Injeta o CSS do loader uma unica vez
824  if (!document.getElementById("atimo_search_loader_style")) {
825    var css =
826      "#atimo_search_loader{position:fixed;inset:0;display:none;align-items:center;" +
827      "justify-content:center;background:rgba(255,255,255,.6);z-index:99999}" +
828      "#atimo_search_loader.is-visible{display:flex}" +
829      "#atimo_search_loader .box{display:flex;align-items:center;gap:12px;" +
830      "background:#fff;padding:16px 22px;border-radius:6px;box-shadow:0 2px 12px rgba(0,0,0,.2);" +
831      "font-size:15px;color:#333}" +
832      "#atimo_search_loader .spinner{width:22px;height:22px;border:3px solid #ccc;" +
833      "border-top-color:#444;border-radius:50%;animation:atimo_spin .8s linear infinite}" +
834      "@keyframes atimo_spin{to{transform:rotate(360deg)}}";
835    var style = document.createElement("style");
836    style.id = "atimo_search_loader_style";
837    style.appendChild(document.createTextNode(css));
838    document.head.appendChild(style);
839  }
840
841  function getLoader() {
842    var $loader = $("#atimo_search_loader");
843    if ($loader.length === 0) {
844      $loader = $(
845        '<div id="atimo_search_loader"><div class="box">' +
846          '<span class="spinner"></span>' +
847          '<span class="text">Searching...</span>' +
848        "</div></div>"
849      );
850      $("body").append($loader);
851    }
852    return $loader;
853  }
854
855  function isSearchReq(settings) {
856    return (
857      settings &&
858      settings.url &&
859      settings.url.indexOf("keyword_search/search.php") > -1
860    );
861  }
862
863  $(document).ajaxSend(function (event, jqxhr, settings) {
864    if (isSearchReq(settings)) {
865      var haystack = (settings.url || "") + "&" + (settings.data || "");
866      var msg = haystack.indexOf("page=") > -1 ? "Loading page..." : "Searching...";
867      getLoader().find(".text").text(msg);
868      getLoader().addClass("is-visible");
869    }
870  });
871
872  $(document).ajaxComplete(function (event, jqxhr, settings) {
873    if (isSearchReq(settings)) {
874      getLoader().removeClass("is-visible");
875    }
876  });
877})();
878
879document.addEventListener("DOMContentLoaded", function() {
880  document.querySelectorAll(".scroll-hint-overlay").forEach(function(overlay) {
881      overlay.addEventListener("click", function() {
882          overlay.classList.add("fade-out");
883          overlay.addEventListener("animationend", function() {
884              overlay.remove();
885          }, { once: true });
886      });
887  });
888
889  document.querySelectorAll(".table-container").forEach(function(container) {
890      container.addEventListener("click", function() {
891          const overlay = container.querySelector(".scroll-hint-overlay");
892          if (overlay) {
893             
894              overlay.classList.add("fade-out");
895              overlay.addEventListener("animationend", function() {
896                  overlay.remove();
897              }, { once: true }); 
898          }
899      });
900  });
901});

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.