PageSourceSearch

https://www.visitadamscountywi.com/assets/controllers/event_recurrence_controller-18bbb693.js

js visitadamscountywi.com collected 2026-09-25 06:08:29 UTC 3,919 bytes, 123 lines download raw bytes

1import { Controller } from "@hotwired/stimulus"
2
3const WEEKDAYS = [
4  "Sunday",
5  "Monday",
6  "Tuesday",
7  "Wednesday",
8  "Thursday",
9  "Friday",
10  "Saturday"
11]
12const WEEK_ORDINALS = ["first", "second", "third", "fourth", "fifth"]
13
14export default class extends Controller {
15  static targets = [
16    "startDate",
17    "pattern",
18    "weeklyOption",
19    "monthlyDateOption",
20    "monthlyWeekdayOption",
21    "endPanel",
22    "repeatUntil"
23  ]
24
25  connect() {
26    this.initialState = {
27      weeklyOptionText: this.weeklyOptionTarget.textContent,
28      monthlyDateOptionText: this.monthlyDateOptionTarget.textContent,
29      monthlyWeekdayOptionText: this.monthlyWeekdayOptionTarget.textContent,
30      endPanelHidden: this.endPanelTarget.classList.contains("hidden"),
31      endPanelAriaHidden: this.endPanelTarget.getAttribute("aria-hidden"),
32      repeatUntilDisabled: this.repeatUntilTarget.disabled,
33      repeatUntilRequired: this.repeatUntilTarget.required,
34      repeatUntilMin: this.repeatUntilTarget.getAttribute("min")
35    }
36
37    this.sync()
38  }
39
40  disconnect() {
41    if (!this.initialState) return
42
43    this.weeklyOptionTarget.textContent = this.initialState.weeklyOptionText
44    this.monthlyDateOptionTarget.textContent = this.initialState.monthlyDateOptionText
45    this.monthlyWeekdayOptionTarget.textContent = this.initialState.monthlyWeekdayOptionText
46    this.endPanelTarget.classList.toggle("hidden", this.initialState.endPanelHidden)
47    this.restoreAttribute(this.endPanelTarget, "aria-hidden", this.initialState.endPanelAriaHidden)
48    this.repeatUntilTarget.disabled = this.initialState.repeatUntilDisabled
49    this.repeatUntilTarget.required = this.initialState.repeatUntilRequired
50    this.restoreAttribute(this.repeatUntilTarget, "min", this.initialState.repeatUntilMin)
51    this.initialState = null
52  }
53
54  sync() {
55    const startsOn = this.dateFromInput(this.startDateTarget.value)
56    this.updateOptionLabels(startsOn)
57
58    const repeats = this.patternTarget.value !== ""
59    this.endPanelTarget.classList.toggle("hidden", !repeats)
60    this.endPanelTarget.setAttribute("aria-hidden", repeats ? "false" : "true")
61    this.repeatUntilTarget.disabled = !repeats
62    this.repeatUntilTarget.required = repeats
63
64    if (startsOn) {
65      this.repeatUntilTarget.min = this.startDateTarget.value
66    } else {
67      this.repeatUntilTarget.removeAttribute("min")
68    }
69  }
70
71  updateOptionLabels(date) {
72    if (!date) {
73      this.weeklyOptionTarget.textContent = "Weekly"
74      this.monthlyDateOptionTarget.textContent = "Monthly on the same date"
75      this.monthlyWeekdayOptionTarget.textContent = "Monthly on the same weekday"
76      return
77    }
78
79    const day = date.getDate()
80    const weekday = WEEKDAYS[date.getDay()]
81    const weekOrdinal = WEEK_ORDINALS[Math.floor((day - 1) / 7)]
82
83    this.weeklyOptionTarget.textContent = `Weekly on ${weekday}`
84    this.monthlyDateOptionTarget.textContent = `Monthly on the ${this.ordinalize(day)}`
85    this.monthlyWeekdayOptionTarget.textContent = `Monthly on the ${weekOrdinal} ${weekday}`
86  }
87
88  dateFromInput(value) {
89    const parts = value.split("-").map(Number)
90    if (parts.length !== 3 || parts.some((part) => !Number.isInteger(part))) return null
91
92    const [year, month, day] = parts
93    const date = new Date(year, month - 1, day)
94
95    if (date.getFullYear() !== year || date.getMonth() !== month - 1 || date.getDate() !== day) return null
96
97    return date
98  }
99
100  ordinalize(number) {
101    const remainder = number % 100
102    if (remainder >= 11 && remainder <= 13) return `${number}th`
103
104    switch (number % 10) {
105    case 1:
106      return `${number}st`
107    case 2:
108      return `${number}nd`
109    case 3:
110      return `${number}rd`
111    default:
112      return `${number}th`
113    }
114  }
115
116  restoreAttribute(element, name, value) {
117    if (value === null) {
118      element.removeAttribute(name)
119    } else {
120      element.setAttribute(name, value)
121    }
122  }
123}

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.