Last active
September 27, 2023 11:23
-
-
Save CarsonSlovoka/7568603fa8bbc4fe287345991e1661e8 to your computer and use it in GitHub Desktop.
example: simple calendar (class)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>Vote</title> | |
</head> | |
<body> | |
<form action="/vote/" method="post"> | |
<label for="name">Name:</label><br> | |
<input type="text" id="name" name="name" required><br><br> | |
<label for="dates">Unavailable Dates:</label><br> | |
<textarea rows="3" cols="100" id="dates" name="dates" readonly></textarea><br> | |
<button type="button" onclick="calendar.toggle()">Select Unavailable Dates</button><br><br> | |
<input type="submit" value="Submit"> | |
</form> | |
<div id="calendar-container"></div> | |
<script> | |
class Calendar { | |
static #SerialNumber = 0 | |
static initCSSStyle() { | |
// 檢查有沒有定義 | |
for (const stylesheet of document.styleSheets) { | |
for (const rule of stylesheet.cssRules) { | |
// rule.cssText // 會包含定義的所有內容 | |
if (rule.selectorText.includes("table.calendar")) { // rule.selectorText: 就是css前面的名稱,例如 "rect:hover + .tooltip" | |
console.info("您已經嘗試自定義table.calendar的樣式,所以不再加入預設的style") | |
return | |
} | |
} | |
} | |
const css = ` | |
table.calendar { | |
display: none; | |
position: absolute; | |
background-color: white; | |
border: 1px solid #ddd; | |
} | |
table.calendar th, table.calendar td { | |
width: 40px; | |
height: 40px; | |
text-align: center; | |
vertical-align: middle; | |
border: 1px solid #ddd; | |
} | |
table.calendar td.selected { | |
background-color: #00f; | |
color: #fff; | |
} | |
` | |
// 加入自定義css | |
const styleSheet = document.createElement("style") | |
styleSheet.innerText = css | |
document.head.appendChild(styleSheet) | |
} | |
constructor(container, currentDate) { | |
this.container = container; | |
this.currentDate = currentDate; | |
this.selectedDates = [] | |
this.id = Calendar.#SerialNumber | |
Calendar.#SerialNumber++ | |
this.table = document.createElement('table') | |
this.table.classList.add("calendar") | |
if (document.calendarMap === undefined) { | |
document.calendarMap = {} | |
} | |
document.calendarMap[`${this.id}`] = this | |
this.table.innerHTML = ` | |
<thead> | |
<tr> | |
<th colspan="1"><button onclick="document.calendarMap[${this.id}].goToPreviousMonth()">◀</button></th> | |
<th colspan="5" id="monthLabel"></th> | |
<th colspan="1"><button onclick="document.calendarMap[${this.id}].goToNextMonth()">▶</button></th> | |
</tr> | |
<tr> | |
<th>Sun</th> | |
<th>Mon</th> | |
<th>Tue</th> | |
<th>Wed</th> | |
<th>Thu</th> | |
<th>Fri</th> | |
<th>Sat</th> | |
</tr> | |
</thead> | |
<tbody> | |
</tbody> | |
`; | |
this.container.appendChild(this.table); | |
} | |
toggle() { | |
if (this.table.style.display === 'none' || this.table.style.display === '') { | |
this.table.style.display = 'block'; | |
this.#render(); | |
} else { | |
this.table.style.display = 'none'; | |
} | |
} | |
goToPreviousMonth() { | |
this.currentDate.setMonth(this.currentDate.getMonth() - 1); | |
this.#render(); | |
} | |
goToNextMonth() { | |
this.currentDate.setMonth(this.currentDate.getMonth() + 1); | |
this.#render(); | |
} | |
#render() { | |
var tbody = this.table.tBodies[0]; | |
tbody.innerHTML = ''; | |
var startDate = new Date(Date.UTC(this.currentDate.getFullYear(), this.currentDate.getMonth(), 1)); | |
var endDate = new Date(Date.UTC(this.currentDate.getFullYear(), this.currentDate.getMonth() + 1, 0)); | |
var row = tbody.insertRow(); | |
for (var d = startDate; d <= endDate; d.setDate(d.getDate() + 1)) { | |
if (row.cells.length === 7) { | |
row = tbody.insertRow(); | |
} | |
var cell = row.insertCell(); | |
cell.innerText = d.getDate(); | |
cell.dataset.date = d.toISOString().slice(0, 10); | |
cell.onclick = (e)=>this.#toggleDate(e) | |
if (this.selectedDates.includes(cell.dataset.date)) { | |
cell.classList.add('selected'); | |
} | |
} | |
document.getElementById('monthLabel').textContent = this.currentDate.toLocaleDateString('default', { month: 'long', year: 'numeric' }); | |
} | |
onToggleDate() { | |
} | |
#toggleDate(event) { | |
var cell = event.target; | |
var date = cell.dataset.date; | |
if (cell.classList.contains('selected')) { | |
cell.classList.remove('selected'); | |
this.selectedDates.splice(this.selectedDates.indexOf(date), 1); | |
} else { | |
cell.classList.add('selected'); | |
this.selectedDates.push(date); | |
} | |
this.onToggleDate() | |
} | |
} | |
Calendar.initCSSStyle() | |
const calendar = new Calendar(document.getElementById('calendar-container'), new Date()); | |
calendar.onToggleDate = ()=> { | |
document.getElementById('dates').value = calendar.selectedDates.join(', '); | |
} | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment