1document.addEventListener("DOMContentLoaded", () => { 2 const dpList = document.querySelectorAll(".duet-date-picker"); 3 const docLanguage = document.querySelector("html")?.getAttribute("lang") || "en"; 4 5 const locales = { 6 en: { 7 buttonLabel: "Choose date", 8 placeholder: "DD/MM/YYYY", 9 selectedDateMessage: "Selected date is", 10 prevMonthLabel: "Previous month", 11 nextMonthLabel: "Next month", 12 monthSelectLabel: "Month", 13 yearSelectLabel: "Year", 14 closeLabel: "Close window", 15 calendarHeading: "Choose a date", 16 dateFormat: "MM/dd/yyyy", 17 timeFormat: "hh:mm aa", 18 firstDay: 0, 19 dayNames: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"], 20 monthNames: [ 21 "January", 22 "February", 23 "March", 24 "April", 25 "May", 26 "June", 27 "July", 28 "August", 29 "September", 30 "October", 31 "November", 32 "December", 33 ], 34 monthNamesShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"], 35 locale: "en", 36 }, 37 ru: { 38 buttonLabel: "ÐÑбеÑиÑе даÑÑ", 39 placeholder: "DD/MM/YYYY", 40 selectedDateMessage: "ÐÑбÑÐ°Ð½Ð½Ð°Ñ Ð´Ð°Ñа", 41 prevMonthLabel: "ÐÑедÑдÑÑий меÑÑÑ", 42 nextMonthLabel: "Ð ÑледÑÑÑем меÑÑÑе", 43 monthSelectLabel: "ÐеÑÑÑ", 44 yearSelectLabel: "Ðод", 45 closeLabel: "ÐакÑÑÑÑ Ð¾ÐºÐ½Ð¾", 46 calendarHeading: "ÐÑбеÑиÑе даÑÑ", 47 dateFormat: "dd.MM.yyyy", 48 timeFormat: "HH:mm", 49 firstDay: 1, 50 dayNames: ["ÐоÑкÑеÑенÑе", "ÐонеделÑник", "ÐÑоÑник", "СÑеда", "ЧеÑвеÑг", "ÐÑÑниÑа", "СÑббоÑа"], 51 daysShort: ["ÐоÑ", "Ðон", "ÐÑо", "СÑе", "ЧеÑ", "ÐÑÑ", "СÑб"], 52 daysMin: ["ÐÑ", "Ðн", "ÐÑ", "СÑ", "ЧÑ", "ÐÑ", "Сб"], 53 monthNames: [ 54 "ЯнваÑÑ", 55 "ФевÑалÑ", 56 "ÐаÑÑ", 57 "ÐпÑелÑ", 58 "Ðай", 59 "ÐÑнÑ", 60 "ÐÑлÑ", 61 "ÐвгÑÑÑ", 62 "СенÑÑбÑÑ", 63 "ÐкÑÑбÑÑ", 64 "ÐоÑбÑÑ", 65 "ÐекабÑÑ", 66 ], 67 monthNamesShort: ["Янв", "Фев", "ÐаÑ", "ÐпÑ", "Ðай", "ÐÑн", "ÐÑл", "Ðвг", "Сен", "ÐкÑ", "ÐоÑ", "Ðек"], 68 locale: "ru", 69 }, 70 he: { 71 buttonLabel: "××ר ת×ר××", 72 placeholder: "DD/MM/YYYY", 73 selectedDateMessage: "×ת×ר×× ×©× ××ר ×××", 74 prevMonthLabel: "×××ש ×§×××", 75 nextMonthLabel: "××××ש ×××", 76 monthSelectLabel: "××Ö¹×ֶש×", 77 yearSelectLabel: "ש×Ö¸× Ö¸×", 78 closeLabel: "ס××ר ××××", 79 calendarHeading: "××ר ת×ר××", 80 dateFormat: "dd/MM/yyyy", 81 timeFormat: "HH:mm", 82 firstDay: 0, 83 dayNames: ["ר×ש××", "×©× ×", "ש××ש×", "ר×××¢×", "×××ש×", "ש×ש×", "ש×ת"], 84 daysShort: ["×׳", "×׳", "×׳", "×׳", "×׳", "×׳", "ש׳"], 85 daysMin: ["×", "×", "×", "×", "×", "×", "ש"], 86 monthNames: [ 87 "×× ××ר", 88 "פ×ר××ר", 89 "×רץ", 90 "×פר××", 91 "×××", 92 "××× ×", 93 "××××", 94 "××××ס×", 95 "ספ×××ר", 96 "×××§×××ר", 97 "× ××××ר", 98 "×צ××ר", 99 ], 100 monthNamesShort: ["×× ×׳", "פ×ר׳", "×רץ", "×פר׳", "×××", "××× ×³", "×××׳", "×××׳", "ספ×׳", "××ק׳", "× ××׳", "×צ×׳"], 101 locale: "he", 102 }, 103 ar: { 104 buttonLabel: "Choose date", 105 placeholder: "DD/MM/YYYY", 106 selectedDateMessage: "Selected date is", 107 prevMonthLabel: "Previous month", 108 nextMonthLabel: "Next month", 109 monthSelectLabel: "Month", 110 yearSelectLabel: "Year", 111 closeLabel: "Close window", 112 calendarHeading: "Choose a date", 113 dateFormat: "dd/MM/yyyy", 114 timeFormat: "hh:mm aa", 115 firstDay: 0, 116 dayNames: ["Ø§ÙØ£ØØ¯", "Ø§ÙØ£Ø«ÙÙÙ", "Ø§ÙØ«Ùاثاء", "Ø§ÙØ£Ø±Ø¨Ø¹Ø§Ø¡", "Ø§ÙØ®Ù ÙØ³", "Ø§ÙØ¬Ù عÙ", "Ø§ÙØ³Ø¨Øª"], 117 daysShort: ["Ø§ÙØ£ØØ¯", "Ø§ÙØ£Ø«ÙÙÙ", "Ø§ÙØ«Ùاثاء", "Ø§ÙØ£Ø±Ø¨Ø¹Ø§Ø¡", "Ø§ÙØ®Ù ÙØ³", "Ø§ÙØ¬Ù عÙ", "Ø§ÙØ³Ø¨Øª"], 118 daysMin: ["Ø§ÙØ£ØØ¯", "Ø§ÙØ£Ø«ÙÙÙ", "Ø§ÙØ«Ùاثاء", "Ø§ÙØ£Ø±Ø¨Ø¹Ø§Ø¡", "Ø§ÙØ®Ù ÙØ³", "Ø§ÙØ¬Ù عÙ", "Ø§ÙØ³Ø¨Øª"], 119 monthNames: [ 120 "ÙÙØ§Ùر", 121 "ÙØ¨Ø±Ø§Ùر", 122 "٠ارس", 123 "أبرÙÙ", 124 "٠اÙÙ", 125 "ÙÙÙÙÙ", 126 "ÙÙÙÙÙ", 127 "أغسطس", 128 "سبت٠بر", 129 "Ø§ÙØªÙبر", 130 "ÙÙÙ٠بر", 131 "Ø¯ÙØ³Ù بر", 132 ], 133 monthNamesShort: [ 134 "ÙÙØ§Ùر", 135 "ÙØ¨Ø±Ø§Ùر", 136 "٠ارس", 137 "أبرÙÙ", 138 "٠اÙÙ", 139 "ÙÙÙÙÙ", 140 "ÙÙÙÙÙ", 141 "أغسطس", 142 "سبت٠بر", 143 "Ø§ÙØªÙبر", 144 "ÙÙÙ٠بر", 145 "Ø¯ÙØ³Ù بر", 146 ], 147 locale: "ar", 148 }, 149 fr: { 150 buttonLabel: "Choose date", 151 placeholder: "DD/MM/YYYY", 152 selectedDateMessage: "Selected date is", 153 prevMonthLabel: "Previous month", 154 nextMonthLabel: "Next month", 155 monthSelectLabel: "Month", 156 yearSelectLabel: "Year", 157 closeLabel: "Close window", 158 calendarHeading: "Choose a date", 159 dateFormat: "dd/MM/yyyy", 160 timeFormat: "HH:mm", 161 firstDay: 1, 162 dayNames: ["Dimanche", "Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi", "Samedi"], 163 daysShort: ["Dim", "Lun", "Mar", "Mer", "Jeu", "Ven", "Sam"], 164 daysMin: ["Di", "Lu", "Ma", "Me", "Je", "Ve", "Sa"], 165 monthNames: [ 166 "Janvier", 167 "Février", 168 "Mars", 169 "Avril", 170 "Mai", 171 "Juin", 172 "Juillet", 173 "Août", 174 "Septembre", 175 "Octobre", 176 "Novembre", 177 "Décembre", 178 ], 179 monthNamesShort: ["Jan", "Fév", "Mars", "Avr", "Mai", "Juin", "Juil", "Août", "Sep", "Oct", "Nov", "Dec"], 180 locale: "fr", 181 }, 182 }; 183 184 const toTwoDigits = (val) => { 185 return val < 10 ? "0" + val : "" + val; 186 }; 187 188 const formatDateByFormat = (date, format) => { 189 const dd = toTwoDigits(date.getDate()); 190 const MM = toTwoDigits(date.getMonth() + 1); 191 const yyyy = date.getFullYear(); 192 return format.replace("dd", dd).replace("MM", MM).replace("yyyy", yyyy); 193 }; 194 195 const parseDateByFormat = (dateString, format) => { 196 if (!dateString) return null; 197 198 const sepMatch = format.match(/[^A-Za-z0-9]/); 199 const sep = sepMatch ? sepMatch[0] : null; 200 201 let formatParts; 202 let dateParts; 203 204 if (sep) { 205 formatParts = format.split(sep); 206 dateParts = dateString.split(sep); 207 } else { 208 formatParts = [format.slice(0, 2), format.slice(2, 4), format.slice(4)]; 209 dateParts = [dateString.slice(0, 2), dateString.slice(2, 4), dateString.slice(4)]; 210 } 211 212 if (formatParts.length !== dateParts.length) return null; 213 214 let day, month, year; 215 for (let i = 0; i < formatParts.length; i++) { 216 const token = formatParts[i]; 217 const part = dateParts[i]; 218 219 if (!part) return null; 220 221 if (token === "dd") { 222 day = Number(part); 223 } else if (token === "MM") {
224 month = Number(part); 225 } else if (token === "yyyy") { 226 year = Number(part); 227 } 228 } 229 230 if (!year || !month || !day) return null; 231 232 const date = new Date(year, month - 1, day); 233 234 if (date.getMonth() + 1 !== month || date.getDate() !== day) return null; 235 return date; 236 }; 237 238 const convertLocalDateToUtcMidnight = (localDate) => { 239 const year = localDate.getFullYear(); 240 const month = localDate.getMonth(); 241 const day = localDate.getDate(); 242 243 return new Date(Date.UTC(year, month, day)); 244 }; 245 246 const escapeRegExp = (value) => { 247 return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); 248 }; 249 250 const buildDateAdapterFromFormat = (format) => { 251 const sepMatch = format.match(/[^A-Za-z0-9]/); 252 const sep = sepMatch ? sepMatch[0] : null; 253 254 const formatParts = sep ? format.split(sep) : [format.slice(0, 2), format.slice(2, 4), format.slice(4)]; 255 const regexParts = formatParts.map((token) => { 256 if (token === "dd") return "(\\d{1,2})"; 257 if (token === "MM") return "(\\d{1,2})"; 258 if (token === "yyyy") return "(\\d{4})"; 259 return "(\\d+)"; 260 }); 261 262 const regexString = sep ? "^" + regexParts.join(escapeRegExp(sep)) + "$" : "^" + regexParts.join("") + "$"; 263 const captureRe = new RegExp(regexString); 264 265 const parse = (dateString = "") => { 266 if (!dateString || typeof dateString !== "string") return null; 267 268 const matchArray = dateString.match(captureRe); 269 270 if (!matchArray) return null; 271 272 let day, month, year; 273 274 for (let i = 0; i < formatParts.length; i++) { 275 const token = formatParts[i]; 276 const part = matchArray[i + 1]; 277 if (!part) return null; 278 279 if (token === "dd") { 280 day = Number(part); 281 } else if (token === "MM") { 282 month = Number(part); 283 } else if (token === "yyyy") { 284 year = Number(part); 285 } 286 } 287 288 if (!day || !month || !year) return null; 289 290 const d = new Date(year, month - 1, day); 291 if (d.getFullYear() !== year || d.getMonth() + 1 !== month || d.getDate() !== day) return null; 292 return d; 293 }; 294 295 const formatDate = (date) => { 296 if (!(date instanceof Date) || Number.isNaN(date.getTime())) return ""; 297 298 const dd = toTwoDigits(date.getDate()); 299 const MM = toTwoDigits(date.getMonth() + 1); 300 const yyyy = date.getFullYear().toString(); 301 302 return formatParts 303 .map((token) => { 304 if (token === "dd") return dd; 305 if (token === "MM") return MM; 306 if (token === "yyyy") return yyyy; 307 return token; 308 }) 309 .join(sep || ""); 310 }; 311 312 return { 313 parse, 314 format: formatDate, 315 }; 316 }; 317 318 dpList.forEach((dp) => { 319 const ct = dp.closest(".floating-label-input"); 320 const hiddenInput = ct.querySelector(".datepickerfieldshadow"); 321 const localeOptions = dp.dataset.locale && locales[dp.dataset.locale] ? locales[dp.dataset.locale] : locales["en"]; 322 323 let isMovedLabel = false; 324 325 dp.localization = localeOptions; 326 dp.firstDayOfWeek = localeOptions.firstDay || 0; 327 dp.dateAdapter = buildDateAdapterFromFormat(localeOptions.dateFormat || "dd/MM/yyyy"); 328 329 dp.addEventListener("duetChange", (event) => { 330 hiddenInput.value = event.detail.value; 331 }); 332 333 const observer = new MutationObserver((mutations) => { 334 mutations.forEach((mutation) => { 335 if (mutation.attributeName === "class") { 336 const dpInputWrap = ct.querySelector(".duet-date__input-wrapper"); 337 const label = ct.querySelector(".floating-label"); 338 339 if (dpInputWrap && label && !isMovedLabel) { 340 label.classList.replace("floating-label", "duet-date__label"); 341 dpInputWrap.appendChild(label); 342 isMovedLabel = true; 343 } 344 } 345 }); 346 }); 347 348 observer.observe(dp, { attributes: true }); 349 350 return { 351 disconnect() { 352 observer.disconnect(); 353 }, 354 }; 355 }); 356});
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.