PageSourceSearch

https://docs.ray.io/en/latest/_static/js/examples.js?v=5ec37523

js ray.io collected 2026-09-24 08:38:57 UTC 6,498 bytes, 209 lines download raw bytes

1/**
2 * Get the status (checked/unchecked) for each filter.
3 *
4 * @returns {Object} Arrays of the name and status of each filter, grouped together into filter
5 * groups.
6 */
7function getFilterStatuses() {
8  const useCases = Array.from(
9    document.querySelectorAll('#use-case-dropdown .checkbox-container'),
10  ).map((label) => {
11    return {
12      name: label.textContent.toLowerCase(),
13      isChecked: label.querySelector('input').checked,
14    };
15  });
16  const libraries = Array.from(
17    document.querySelectorAll('#library-dropdown .checkbox-container'),
18  ).map((label) => {
19    return {
20      name: label.textContent.toLowerCase(),
21      isChecked: label.querySelector('input').checked,
22    };
23  });
24  const frameworks = Array.from(
25    document.querySelectorAll('#framework-dropdown .checkbox-container'),
26  ).map((label) => {
27    return {
28      name: label.textContent.toLowerCase(),
29      isChecked: label.querySelector('input').checked,
30    };
31  });
32  const contributor = Array.from(
33    document.querySelectorAll('#all-examples-dropdown .checkbox-container'),
34  ).map((label) => {
35    const inputElement = label.querySelector('input');
36    return {
37      name: inputElement.id.replace('-checkbox', ''),
38      isChecked: inputElement.checked,
39    };
40  });
41  return {
42    useCases,
43    libraries,
44    frameworks,
45    contributor,
46  };
47}
48
49/**
50 * Test whether the tags of the given example panel match the requested filters.
51 *
52 * @param {any} tags Tags of the example panel
53 * @param {any} filters Filter statuses for all the filter groups; this should be the output of
54 * getFilterStatuses.
55 * @returns {bool} True if the example panel matches the filters, or not.
56 */
57function panelMatchesFilters(tags, filters) {
58  return Object.entries(filters).every(([group, groupTags]) => {
59    // If there is no selection, consider the panel to be matched
60    if (groupTags.filter(({isChecked}) => isChecked).length === 0) {
61      return true;
62    }
63
64    // If "Any" is checked, consider the panel to be matched
65    if (
66      groupTags.filter(({name, isChecked}) => name === 'any' && isChecked)
67        .length > 0
68    ) {
69      return true;
70    }
71
72    // Otherwise show the panel if any checked item matches the tags of the panel
73    return groupTags
74      .filter(({isChecked}) => isChecked)
75      .some(({name}) => tags.includes(name));
76  });
77}
78
79/** Apply the currently selected filters to the example gallery, showing only the relevant examples. */
80function applyFilter() {
81  const noMatchesElement = document.getElementById('no-matches');
82  const panels = document.querySelectorAll('.example');
83  const filters = getFilterStatuses();
84  const searchTerm = document
85    .getElementById('examples-search-input')
86    .value.toLowerCase();
87
88  // Show all panels before hiding the ones that need to be hidden.
89  panels.forEach((panel) => panel.classList.remove('hidden'));
90
91  // Check the title and tags of each example panel. If the tags match and the search term matches,
92  // show the panel.
93  panels.forEach((panel) => {
94    const title = panel
95      .querySelector('.example-title')
96      .textContent.toLowerCase();
97    const tags = panel
98      .querySelector('.example-tags')
99      .textContent.toLowerCase()
100      .concat();
101    const other_keywords = panel
102      .querySelector('.example-other-keywords')
103      .textContent.toLowerCase();
104    const keywords = `${tags} ${other_keywords}`;
105    const matchesSearch =
106      title.includes(searchTerm) || keywords.includes(searchTerm);
107    const matchesTags = panelMatchesFilters(keywords, filters);
108
109    // Hide panels that have no match
110    if (matchesSearch && matchesTags) {
111      panel.classList.remove('hidden');
112    } else {
113      panel.classList.add('hidden');
114    }
115  });
116
117  // If none are shown, show the "no matches" graphic.
118  if (document.querySelectorAll('.example:not(.hidden)').length === 0) {
119    noMatchesElement.classList.remove('hidden');
120  } else {
121    noMatchesElement.classList.add('hidden');
122  }
123
124  // Set the URL to match the active filters using query parameters.
125  const selectedTags = Object.entries(filters).map(([group, groupTags]) => {
126    return {
127      group,
128      selected: groupTags
129        .filter(({isChecked}) => isChecked)
130        .map(({name}) => name),
131    };
132  });
133
134  const queryParam = selectedTags
135    .filter(({group, selected}) => selected.length > 0)
136    .map(({group, selected}) => `${group}=${selected.join(',')}`)
137    .join('&');
138
139  history.replaceState(
140    null,
141    null,
142    queryParam.length === 0 ? location.pathname : `?${queryParam}`,
143  );
144}
145
146window.addEventListener('load', () => {
147  // Listen for filter checkbox clicks.
148  document.querySelectorAll('.filter-checkbox').forEach((tag) => {
149    tag.addEventListener('click', () => applyFilter());
150  });
151
152  // Add event listener for keypresses in the search bar.
153  document
154    .getElementById('examples-search-input')
155    .addEventListener('keyup', (event) => {
156      event.preventDefault();
157      applyFilter();
158    });
159
160  // Add the ability to provide URL query parameters to filter examples on page load.
161  const urlParams = new URLSearchParams(window.location.search);
162  if (urlParams.size > 0) {
163    urlParams.forEach((params) => {
164      params.split(',').forEach((param) => {
165        const element = document.getElementById(`${param}-checkbox`);
166        if (element) {
167          element.checked = true;
168        }
169      });
170    });
171  }
172
173  // Apply the filter in case there are URL query parameters.
174  applyFilter();
175
176  const dropdowns = Array.from(
177    document.querySelectorAll('.dropdown-content'),
178  ).map((dropdown) => {
179    return {
180      dropdown,
181      input: dropdown.parentNode.querySelector('input'),
182      inputContainer: dropdown.parentNode,
183    };
184  });
185  document.addEventListener('click', (event) => {
186    let targetEl = event.target; // clicked element
187
188    do {
189      const unclicked = dropdowns.filter(({dropdown, inputContainer}) => {
190        return !(targetEl == dropdown || targetEl == inputContainer);
191      });
192      if (unclicked.length !== dropdowns.length) {
193        // There has been a click inside one of the dropdowns. Close unclicked dropdowns and return.
194        unclicked.forEach(({input}) => {
195          input.checked = false;
196        });
197        return;
198      }
199
200      // Go up the DOM.
201      targetEl = targetEl.parentNode;
202    } while (targetEl);
203
204    // This is a click outside. Close all dropdowns.
205    dropdowns.forEach(({dropdown, input}) => {
206      input.checked = false;
207    });
208  });
209});

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.