PageSourceSearch

https://rootscs.org/themes/contrib/material_base/js/misc.js?tjzkg5

js rootscs.org collected 2026-10-04 05:21:28 UTC 10,856 bytes, 299 lines download raw bytes

1((Drupal, once) => {
2  'use strict';
3
4  Drupal.behaviors.materialBaseFunctions = {
5    attach: (context, settings) => {
6
7      // Header background image and navbar effects.
8      const header = document.getElementById('header');
9      const headerHeight = header.offsetHeight;
10      const headerBg = document.querySelector('.navbar-fixed #header-bg');
11      const headerContent = document.querySelector('.navbar-fixed #header-content');
12      const navbar = document.querySelector('.navbar-fixed #navbar');
13      const headerBgHeight = headerHeight - 192;
14
15      const handleScroll = () => {
16        const scrollPercent = (headerBgHeight - window.scrollY) / headerBgHeight;
17        if (scrollPercent >= 0) {
18          headerBg.style.opacity = scrollPercent;
19          headerContent.style.opacity = scrollPercent;
20        }
21
22        if (window.scrollY > headerHeight - 128) {
23          navbar.classList.add('navbar-bg');
24        } else {
25          navbar.classList.remove('navbar-bg');
26        }
27
28        if (window.scrollY > headerHeight - 64) {
29          navbar.classList.add('navbar-shadow');
30        } else {
31          navbar.classList.remove('navbar-shadow');
32        }
33      }
34
35      // Drawer.
36      const handleDrawerOpen = (e) => {
37        e.stopPropagation();
38        e.preventDefault();
39        document.body.classList.add('drawer-open');
40      }
41
42      const handleDrawerClose = (e) => {
43        e.stopPropagation();
44        e.preventDefault();
45        document.body.classList.remove('drawer-open');
46      }
47
48      let touchstartX = 0;
49      let touchendX = 0;
50
51      const handleTouchStart = (event) => {
52        touchstartX = event.changedTouches[0].screenX;
53      }
54
55      const handleTouchEnd = (event) => {
56        touchendX = event.changedTouches[0].screenX;
57        if (touchendX < touchstartX && touchendX - touchstartX < -50) {
58          handleDrawerClose(event);
59        }
60      }
61
62      // Smooth scroll for anchor links.
63      const getTopOffset = () => {
64        let fixedHeight = 24;
65        const bodyClasses = document.body.classList;
66
67        if (bodyClasses.contains('navbar-fixed')) {
68          fixedHeight += 64;
69        }
70
71        if (bodyClasses.contains('toolbar-vertical')) {
72          fixedHeight += 40;
73        }
74
75        if (bodyClasses.contains('toolbar-horizontal')) {
76          fixedHeight += 40;
77
78          if (bodyClasses.contains('toolbar-tray-open')) {
79            fixedHeight += 40;
80          }
81        }
82
83        return fixedHeight;
84      };
85
86      const handleSmoothScroll = (targetId, e = null) => {
87        if (e) {
88          e.preventDefault();
89        }
90
91        const target = document.querySelector(targetId);
92        if (!target) {
93          return;
94        }
95
96        const targetOffsetTop = target.getBoundingClientRect().top + window.scrollY;
97        window.scrollTo({
98          top: targetOffsetTop - getTopOffset(),
99          behavior: 'smooth'
100        });
101        if (history.pushState) {
102          history.pushState(null, null, targetId);
103        } else {
104          window.location.hash = targetId;
105        }
106      };
107
108      // Collapsible panels.
109      const handleCollapsiblePanel = (toggle) => {
110        const target = document.querySelector(`#${toggle.dataset.target}`);
111        if (!target) {
112          return;
113        }
114
115        // Updating classes explicitly instead of toggle to reduce wrong usage.
116        if (window.getComputedStyle(target).display === 'none') {
117          slideDown(target, 200);
118          target.classList.add('expanded');
119          toggle.classList.add('expanded');
120        }
121        else {
122          slideUp(target, 200);
123          target.classList.remove('expanded');
124          toggle.classList.remove('expanded');
125        }
126      };
127
128      // Dropdown menus.
129      const handleMenuDropdown = (e, toggle) => {
130        e.stopPropagation();
131        e.preventDefault();
132        toggle.classList.remove('tooltip-expanded');
133        const tooltip = toggle.querySelector('.tooltip');
134        if (tooltip) {
135          tooltip.classList.remove('tooltip-expanded');
136        }
137        const targetId = `#${toggle.dataset.target}`;
138        const target = document.querySelector(targetId);
139        document.querySelectorAll(`.menu-dropdown:not(${targetId})`).forEach(dropdown => {
140          slideUp(dropdown, 200);
141          dropdown.classList.remove('expanded');
142        });
143        document.querySelectorAll(`.menu-dropdown-toggle:not([data-target="${toggle.dataset.target}"])`).forEach(toggle => {
144          toggle.classList.remove('dropdown-expanded');
145        });
146        if (!target) {
147          return;
148        }
149        if (window.getComputedStyle(target).display === 'none') {
150          slideDown(target, 200);
151          target.classList.add('expanded');
152          toggle.classList.add('dropdown-expanded');
153        }
154        else {
155          slideUp(target, 200);
156          target.classList.remove('expanded');
157          toggle.classList.remove('dropdown-expanded');
158        }
159      }
160
161      // Handling boxed textarea filled state.
162      const handleBoxedTextareaFilledState = (element, textarea) => {
163        if (textarea.value !== '') {
164          element.classList.add('filled');
165        }
166        else {
167          element.classList.remove('filled');
168        }
169      }
170
171      // Handling filled state for boxed textarea with CodeMirror editor.
172      const handleBoxedTextareaCodemirrorFilledState = (element, editor) => {
173        if (editor.getValue().trim()) {
174          element.classList.add('filled');
175        } else {
176          element.classList.remove('filled');
177        }
178      };
179
180      // Global behaviors of the page.
181      once('materialBaseFunctions', 'html').forEach((element) => {
182
183        // Header background image and navbar effects.
184        handleScroll();
185        document.addEventListener('scroll', handleScroll);
186
187        // Drawer.
188        const drawer = document.getElementById('drawer');
189        const drawerOverlay = document.getElementById('drawer-overlay');
190        const navbarMenuToggle = document.getElementById('navbar-menu-toggle');
191        const drawerMenuClose = document.getElementById('drawer-menu-close');
192
193        navbarMenuToggle.addEventListener('click', handleDrawerOpen);
194
195        drawerOverlay.addEventListener('click', handleDrawerClose);
196
197        drawerMenuClose.addEventListener('click', handleDrawerClose);
198
199        drawer.addEventListener('touchstart', handleTouchStart);
200        drawer.addEventListener('touchend', handleTouchEnd);
201
202        drawerOverlay.addEventListener('touchstart', handleTouchStart);
203        drawerOverlay.addEventListener('touchend', handleTouchEnd);
204
205        // Smooth scroll for anchor links on page load.
206        if (window.location.hash) {
207          // Small timeout needs for applying body classes.
208          setTimeout(() => handleSmoothScroll(window.location.hash), 100);
209        }
210
211        // Collapsing dropdowns on page click.
212        const menuDropdownToggles = document.querySelectorAll('.menu-dropdown-toggle');
213        const menuDropdowns = document.querySelectorAll('.menu-dropdown');
214
215        document.addEventListener('click', () => {
216          menuDropdowns.forEach(dropdown => {
217            slideUp(dropdown, 200);
218            dropdown.classList.remove('expanded');
219          });
220          menuDropdownToggles.forEach(toggle => {
221            toggle.classList.remove('dropdown-expanded');
222          });
223        });
224
225      });
226
227      // Attaching ripple effect to buttons and surfaces.
228      once('rippleRipple', '.ripple', context).forEach(element => new Ripple(element));
229      once('btnRipple', '.btn', context).forEach(element => new Ripple(element));
230      once('fabRipple', '.fab', context).forEach(element => new Ripple(element));
231
232      // Smooth scroll for anchor links.
233      once('anchorLinkClick', 'a[href^="#"]:not([href="#"])', context).forEach(element => {
234        element.addEventListener('click', e => handleSmoothScroll(element.hash, e));
235      });
236
237      once('fullPathWithAnchorLinkClick', `a[href^="${window.location.pathname}#"]`, context).forEach(element => {
238        element.addEventListener('click', e => handleSmoothScroll(element.hash, e));
239      });
240
241      // Collapsible panels.
242      once('collapsiblePanelToggleClick', '.collapsible-toggle', context).forEach(element => {
243        element.addEventListener('click', () => handleCollapsiblePanel(element));
244      });
245
246      // Tooltips.
247      once('tooltipBehavior', '.tooltip', context).forEach(element => {
248        element.addEventListener('mouseenter', () => element.classList.add('tooltip-expanded'));
249        element.addEventListener('mouseleave', () => element.classList.remove('tooltip-expanded'));
250      });
251
252      // Menu Dropdown.
253      once('menuDropdownToggleClick', '.menu-dropdown-toggle', context).forEach(element => {
254        element.addEventListener('click', e => handleMenuDropdown(e, element));
255      });
256
257      // Handling common form item focus state.
258      once('formItemFocusState', '.form-item > input', context).forEach(element => {
259        element.addEventListener('focus', () => element.parentElement.classList.add('focused'));
260        element.addEventListener('blur', () => element.parentElement.classList.remove('focused'));
261      });
262
263      // Handling textarea form item focus state.
264      once('formItemTextareaFocusState', '.form-item.form-type-textarea', context).forEach(element => {
265        const textarea = element.querySelector('textarea');
266        textarea.addEventListener('focus', () => element.classList.add('focused'));
267        textarea.addEventListener('blur', () => element.classList.remove('focused'));
268      });
269
270      // Handling boxed textarea state.
271      once('formItemBoxedTextareaState', '.form-item.textarea-boxed', context).forEach(element => {
272        // Handling empty/filled state for regular field.
273        const textarea = element.querySelector('textarea');
274        // Initial state.
275        handleBoxedTextareaFilledState(element, textarea);
276        // Updating state after input.
277        textarea.addEventListener('keyup', () => handleBoxedTextareaFilledState(element, textarea));
278
279        // Handling focused and filled state for boxed textarea with CodeMirror editor.
280        let editorElement;
281        setTimeout(() => {
282          editorElement = element.querySelector('.CodeMirror');
283          if (!editorElement) {
284            return;
285          }
286
287          const editor = editorElement.CodeMirror;
288          // Initial state.
289          handleBoxedTextareaCodemirrorFilledState(element, editor);
290          // Update state on events.
291          editor.on('focus', () => element.classList.add('focused'));
292          editor.on('blur', () => element.classList.remove('focused'));
293          editor.on('change', () => handleBoxedTextareaCodemirrorFilledState(element, editor));
294        }, 100);
295      });
296
297    }
298  };
299}) (Drupal, once);

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.