PageSourceSearch

https://www.golden-careers.com/assets/sites/controllers/call_to_action/job_alert_field_controller-863fb0e3.js

js golden-careers.com collected 2026-10-04 20:25:35 UTC 5,287 bytes, 106 lines download raw bytes

1import {Controller} from '@hotwired/stimulus'
2
3export default class extends Controller {
4  connect() {
5    this.observers = []
6    this.setupSelectize()
7    this.fixSelectizeForAda()
8  }
9
10  disconnect() {
11    this.observers.forEach(o => o.disconnect())
12  }
13
14  setupSelectize() {
15    const defaultDelimiter = '|';
16    const maxLimit = js_vars.configuration.job_alert_field_selection_limit;
17    const defaultMaxOptions = 1500; // Selectize defaults to 1000 rendered options, too low for custom fields with large option lists
18    // TODO: get rid of the loops
19    for (const field of ['departments', 'categories', 'levels', 'employment_types', 'workplace_types', 'locations', ...js_vars.configuration.field_mapping_names]) {
20      for (const select of this.element.querySelectorAll(`select[data-job-alert-field="${field}"]`)) {
21        const fieldName = select.dataset.fieldName
22        const $select = $ctj(select)
23        $select.selectize({
24          onInitialize: () => {
25            this.setAriaLabelsOnSelectizeInput(select, fieldName)
26            this.setAriaLabelsOnSelectizeDropdown(select)
27          },
28          delimiter: defaultDelimiter,
29          maxItems: maxLimit,
30          maxOptions: defaultMaxOptions,
31          valueField: 'value',
32          labelField: 'label',
33          searchField: 'label',
34          closeAfterSelect: true,
35          render: {
36            item: (item, escape) => `<div class="item">${escape(item.label)}</div>`,
37            option: (item, escape) => `<div id="selectize-option-${select.dataset.jobAlertField}-${escape(item.value)}" role="option" class="option" aria-label="${escape(item.label)}" aria-selected="false">${escape(item.label)}</div>`
38          },
39          onDropdownOpen: () => this.updateSelectizeInputAriaExpanded(select, true),
40          onDropdownClose: () => this.updateSelectizeInputAriaExpanded(select, false),
41          onItemAdd: () => {this.updateSelectizeItemCount(select); this.updateSelectizeDropdownsAriaLabel(select)},
42          onItemRemove: () => {this.updateSelectizeItemCount(select); this.updateSelectizeDropdownsAriaLabel(select)}
43        })
44        const control = select.nextElementSibling
45        const observer = new MutationObserver(() => {
46          const active = control.querySelector('.option.active')
47          const input = control.querySelector('.selectize-input input')
48          active ? input.setAttribute('aria-activedescendant', active.id) : input.removeAttribute('aria-activedescendant')
49        })
50        observer.observe(control.querySelector('.selectize-dropdown-content'), {subtree: true, attributes: true, attributeFilter: ['class']})
51        this.observers.push(observer)
52      }
53    }
54  }
55
56  fixSelectizeForAda() {
57    for (const label of this.element.querySelectorAll('label.ada-remove-selectize')) {
58      label.setAttribute('aria-hidden', 'true')
59    }
60  }
61
62  setAriaLabelsOnSelectizeInput(select, fieldName) {
63    const selectizeInputInput = select.nextElementSibling.querySelector('.selectize-input input')
64    selectizeInputInput.setAttribute('role', 'combobox')
65    selectizeInputInput.setAttribute('aria-haspopup', 'listbox')
66    selectizeInputInput.setAttribute('aria-controls', `selectize-dropdown-${select.dataset.jobAlertField}`)
67    selectizeInputInput.setAttribute('aria-expanded', 'false')
68    selectizeInputInput.setAttribute('aria-label', fieldName)
69  }
70
71  setAriaLabelsOnSelectizeDropdown(select) {
72    const dropdown = select.nextElementSibling.querySelector('.selectize-dropdown')
73    dropdown.setAttribute('id', `selectize-dropdown-${select.dataset.jobAlertField}`)
74    dropdown.setAttribute('role', 'listbox')
75    dropdown.setAttribute('aria-multiselectable', 'true')
76    dropdown.querySelector('.selectize-dropdown-content').setAttribute('role', 'presentation')
77    this.updateSelectizeDropdownsAriaLabel(select)
78  }
79
80  updateSelectizeDropdownsAriaLabel(select) {
81    const selectedLabels = select.selectize.getValue().map(v => select.selectize.options[v].label)
82    let label = select.dataset.listboxLabel
83    if (selectedLabels.length > 0) {
84      label += '. ' + select.dataset.selectedSuffix.replace('%{items}', selectedLabels.join(', '))
85    }
86    select.nextElementSibling.querySelector('.selectize-dropdown').setAttribute('aria-label', label)
87  }
88
89  updateSelectizeInputAriaExpanded(select, expanded) {
90    const selectizeInputInput = select.nextElementSibling.querySelector('.selectize-input input')
91    selectizeInputInput.setAttribute('aria-expanded', expanded)
92  }
93
94  updateSelectizeItemCount(select) {
95    const selectedValues = select.selectize.getValue()
96    const itemsSelected = selectedValues.length
97    const totalDropdownOptions = Object.keys(select.selectize.options).length
98    const fieldName = select.dataset.fieldName
99    const dropdownItemsSelectedLabel = select.dataset.dropdownLabel.replace('%{items_selected}', itemsSelected).replace('%{total_dropdown_options}', totalDropdownOptions).replace('%{field_name}', fieldName)
100    const selectedLabels = selectedValues.map(v => select.selectize.options[v].label)
101    const countAnnouncer = this.element.querySelector(`span[data-count-for="${select.id}"]`)
102    setTimeout(() => {
103      countAnnouncer.textContent = [...selectedLabels, dropdownItemsSelectedLabel].join(', ')
104    }, 200)
105  }
106}

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.