Created
March 10, 2016 15:27
-
-
Save gourytch/815fbd442b747e01ebfe to your computer and use it in GitHub Desktop.
Simple Calenar
This file contains hidden or 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
| package main | |
| import ( | |
| "bytes" | |
| "fmt" | |
| "io" | |
| "net/http" | |
| "time" | |
| ) | |
| const ( | |
| SERVER_ADDR = ":8008" | |
| ) | |
| type DayCell struct { | |
| pit time.Time | |
| dow int | |
| text string | |
| bold_u bool | |
| bold_d bool | |
| bold_l bool | |
| bold_r bool | |
| } | |
| // from time/time.go | |
| func isLeap(year int) bool { | |
| return year%4 == 0 && (year%100 != 0 || year%400 == 0) | |
| // or | |
| // return time.Date(year, time.December, 31, 0,0,0,0, time.Local).YearDay() > 365 | |
| } | |
| func DaysInMonth(year int, month time.Month) int { | |
| // корявый метод определения количества дней | |
| switch month { | |
| case time.January, | |
| time.March, | |
| time.May, | |
| time.July, | |
| time.August, | |
| time.October, | |
| time.December: | |
| return 31 | |
| case time.April, | |
| time.June, | |
| time.September, | |
| time.November: | |
| return 30 | |
| case time.February: | |
| if isLeap(year) { | |
| return 29 | |
| } else { | |
| return 28 | |
| } | |
| } | |
| return 0 | |
| } | |
| func Holiday(t time.Time) bool { | |
| wd := t.Weekday() | |
| return wd == time.Saturday || wd == time.Sunday | |
| } | |
| func Weekday0(t time.Time) int { // monday->0, sunday->6 | |
| switch t.Weekday() { | |
| case time.Monday: | |
| return 0 | |
| case time.Tuesday: | |
| return 1 | |
| case time.Wednesday: | |
| return 2 | |
| case time.Thursday: | |
| return 3 | |
| case time.Friday: | |
| return 4 | |
| case time.Saturday: | |
| return 5 | |
| case time.Sunday: | |
| return 6 | |
| } | |
| return -1 | |
| } | |
| func Borders(t time.Time) (left, top, right, bottom bool) { | |
| // left - если понедельник или если начало месяца | |
| // right - если суббота или если конец месяца | |
| // top - если граничит с предыдущим месяцем (день <= 7) | |
| // bottom - если граничит с последующим месяцем | |
| // (последний день месяца < день + 7) | |
| dow := Weekday0(t) | |
| day := t.Day() | |
| last_day := DaysInMonth(t.Year(), t.Month()) | |
| left = (dow == 0) || (day == 1) | |
| right = (dow == 6) || (day == last_day) | |
| top = (day <= 7) | |
| bottom = (last_day < day+7) | |
| return | |
| } | |
| func render_css() string { | |
| color := []int{ | |
| 0xbefbff, // Jan | |
| 0xbee3ff, // Feb | |
| 0xb2ffc1, // Mar | |
| 0x7bec90, // Apr | |
| 0x46ff69, // May | |
| 0xa5ffb6, // Jun | |
| 0xe0ffa5, // Jul | |
| 0xcae596, // Aug | |
| 0xffeca8, // Sep | |
| 0xfae0ff, // Oct | |
| 0x74c6ff, // Nov | |
| 0xefe5f6, // Dec | |
| } | |
| var buf bytes.Buffer | |
| for m := 1; m <= 12; m++ { | |
| buf.WriteString(fmt.Sprintf(".dom%d {background-color: #%06x;}\n", m, color[m-1])) | |
| } | |
| buf.WriteString("table.calendar {border-collapse: collapse;}\n") | |
| buf.WriteString("table.calendar td {text-align: right;}\n") | |
| buf.WriteString(".border_left {border-left: 1px solid black;}\n") | |
| buf.WriteString(".border_right {border-right: 1px solid black;}\n") | |
| buf.WriteString(".border_top {border-top: 1px solid black;}\n") | |
| buf.WriteString(".border_bottom {border-bottom: 1px solid black;}\n") | |
| buf.WriteString(".holiday {color: red;}\n") | |
| buf.WriteString(".today {font-weight: bold;}\n") | |
| return buf.String() | |
| } | |
| func render_splitted_calendar(year int) string { | |
| // генерим потоком день за днём, | |
| // если встречаем начало нового месяца - генерим код со спаном и названием | |
| // если встречаем начало недели, но не месяца - генерим код начала | |
| // если встречаем конец недели, но не месяца - генерим код с концовкой | |
| // если встречаем конец месяца - генерим код со спаном и концовкой | |
| t1 := time.Date(year, 1, 1, 0, 0, 0, 0, time.Local) | |
| t2 := time.Date(year+1, 1, 1, 0, 0, 0, 0, time.Local) | |
| var buf bytes.Buffer | |
| buf.WriteString("<table class='calendar' border='1'>\n") | |
| buf.WriteString(fmt.Sprintf("<tr class='year'><td class='year' colspan='7'>%d</td></tr>\n", year)) | |
| for t := t1; t.Before(t2); t = t.AddDate(0, 0, 1) { // каждый день | |
| d := t.Day() | |
| m := t.Month() | |
| wd := Weekday0(t) | |
| dim := DaysInMonth(year, m) | |
| switch { // обрабатываем возможное начало месяца или недели | |
| case d == 1: // начало месяца | |
| name := m.String() | |
| buf.WriteString(fmt.Sprintf("<tr class='month'><td class='month' colspan='7'>%s</td></tr>\n", name)) | |
| switch wd { // сколько колонок пропустить | |
| case 0: // понедельник, ничего не пропускаем | |
| buf.WriteString("<tr>") | |
| case 1: // вторник, пропускаем колонку | |
| buf.WriteString("<tr><td class='startmonth'></td>") | |
| default: // пропускаем от 2х до 6 дней | |
| buf.WriteString(fmt.Sprintf("<tr><td class='startmonth' colspan='%d'></td>", wd)) | |
| } | |
| case wd == 0: // начало недели | |
| buf.WriteString("<tr class='week'>") | |
| } | |
| // обрабатываем сам день недели | |
| classname := fmt.Sprintf("dom%d", m) | |
| left, top, right, bottom := Borders(t) | |
| holiday := Holiday(t) | |
| if left { | |
| classname += " border_left" | |
| } | |
| if right { | |
| classname += " border_right" | |
| } | |
| if top { | |
| classname += " border_top" | |
| } | |
| if bottom { | |
| classname += " border_bottom" | |
| } | |
| if holiday { | |
| classname += " holiday" | |
| } | |
| buf.WriteString(fmt.Sprintf("<td class='%s'>%d</td>", classname, d)) | |
| switch { // обрабатываем возможно оконачание месяца или недели | |
| case d == dim: // конец месяца | |
| switch wd { // сколько колонок добить | |
| case 6: // воскресенье, ничего не добиваем | |
| buf.WriteString("</tr>\n") | |
| case 5: // суббота добавим одну колонку | |
| buf.WriteString("<td class='endmonth'></td></tr>\n") | |
| default: // добавляем от 2х до 6 дней | |
| buf.WriteString(fmt.Sprintf("<td class='endmonth' colspan='%d'></td></tr>\n", 6-wd)) | |
| } | |
| case wd == 6: // конец недели | |
| buf.WriteString("</tr>\n") | |
| } // end switch d|wd | |
| } // end for | |
| buf.WriteString("</table>\n") | |
| return buf.String() | |
| } | |
| func render_streamed_calendar(year int) string { | |
| // генерим потоком день за днём, | |
| // если встречаем начало нового месяца - генерим код со спаном и названием | |
| // если встречаем начало недели, но не месяца - генерим код начала | |
| // если встречаем конец недели, но не месяца - генерим код с концовкой | |
| // если встречаем конец месяца - генерим код со спаном и концовкой | |
| t1 := time.Date(year, 1, 1, 0, 0, 0, 0, time.Local) | |
| t2 := time.Date(year+1, 1, 1, 0, 0, 0, 0, time.Local) | |
| now := time.Now() | |
| var buf bytes.Buffer | |
| buf.WriteString("<table class='calendar'>\n") | |
| buf.WriteString(fmt.Sprintf("<tr class='year'><td class='year' colspan='7'>%d</td></tr>\n", year)) | |
| for t := t1; t.Before(t2); t = t.AddDate(0, 0, 1) { // каждый день | |
| d := t.Day() | |
| m := t.Month() | |
| wd := Weekday0(t) | |
| dim := DaysInMonth(year, m) | |
| switch { // обрабатываем возможное начало месяца или недели | |
| case d == 1 && m == 1: | |
| switch wd { // сколько колонок пропустить | |
| case 0: // понедельник, ничего не пропускаем | |
| buf.WriteString("<tr>") | |
| case 1: // вторник, пропускаем колонку | |
| buf.WriteString("<tr><td class='startmonth'></td>") | |
| default: // пропускаем от 2х до 6 дней | |
| buf.WriteString(fmt.Sprintf("<tr><td class='startmonth' colspan='%d'></td>", wd)) | |
| } | |
| case wd == 0: // начало недели | |
| buf.WriteString("<tr class='week'>") | |
| } | |
| // обрабатываем сам день недели | |
| classname := fmt.Sprintf("dom%d", m) | |
| left, top, right, bottom := Borders(t) | |
| holiday := Holiday(t) | |
| if left { | |
| classname += " border_left" | |
| } | |
| if right { | |
| classname += " border_right" | |
| } | |
| if top { | |
| classname += " border_top" | |
| } | |
| if bottom { | |
| classname += " border_bottom" | |
| } | |
| if holiday { | |
| classname += " holiday" | |
| } | |
| if t.Year() == now.Year() && t.YearDay() == now.YearDay() { | |
| classname += " today" | |
| } | |
| tooltip := t.Format("_2 January, Monday") | |
| buf.WriteString(fmt.Sprintf("<td class='%s' title='%s'>%d</td>", classname, tooltip, d)) | |
| switch { // обрабатываем возможно оконачание месяца или недели | |
| case d == dim && m == 12: // конец месяца | |
| switch wd { // сколько колонок добить | |
| case 6: // воскресенье, ничего не добиваем | |
| buf.WriteString("</tr>\n") | |
| case 5: // суббота добавим одну колонку | |
| buf.WriteString("<td class='endmonth'></td></tr>\n") | |
| default: // добавляем от 2х до 6 дней | |
| buf.WriteString(fmt.Sprintf("<td class='endmonth' colspan='%d'></td></tr>\n", 6-wd)) | |
| } | |
| case wd == 6: // конец недели | |
| buf.WriteString("</tr>\n") | |
| } // end switch d|wd | |
| } // end for | |
| buf.WriteString("</table>\n") | |
| return buf.String() | |
| } | |
| func render_page(year int) string { | |
| var buf bytes.Buffer | |
| buf.WriteString("<!DOCTYPE html>\n") | |
| buf.WriteString("<html>\n") | |
| buf.WriteString("<head>\n") | |
| buf.WriteString("<style>\n") | |
| buf.WriteString(render_css()) | |
| buf.WriteString("</style>\n") | |
| buf.WriteString("</head>\n") | |
| buf.WriteString("<body>\n") | |
| //buf.WriteString(render_splitted_calendar(year)) | |
| buf.WriteString(render_streamed_calendar(year)) | |
| buf.WriteString("</body>\n") | |
| buf.WriteString("</html>\n") | |
| return buf.String() | |
| } | |
| func handleRoot(w http.ResponseWriter, rq *http.Request) { | |
| w.Header().Set("Content-Type", "text/html; charset=utf-8") | |
| w.WriteHeader(http.StatusOK) | |
| io.WriteString(w, render_page(2016)) | |
| } | |
| func serve() { | |
| http.HandleFunc("/", handleRoot) | |
| http.ListenAndServe(SERVER_ADDR, nil) | |
| } | |
| func main() { | |
| serve() | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment