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.