adam@2
|
1 style calendar
|
adam@2
|
2 style prev
|
adam@2
|
3 style this
|
adam@2
|
4 style next
|
adam@2
|
5 style weekday
|
adam@2
|
6 style curday
|
adam@2
|
7 style otherday
|
adam@2
|
8
|
adam@2
|
9 datatype month = Prev | This | Next
|
adam@2
|
10
|
adam@2
|
11 type t = {Month : source {ThisMonth : int, Year : int,
|
adam@2
|
12 ThisMonthLength : int, PrevMonthLength : int,
|
adam@2
|
13 MondayMonth : month, MondayDay : int,
|
adam@2
|
14 PrevMonthName : string, ThisMonthName : string, NextMonthName : string},
|
adam@2
|
15 Day : source int}
|
adam@2
|
16
|
adam@2
|
17 fun pad len n =
|
adam@2
|
18 let
|
adam@2
|
19 val s = show n
|
adam@2
|
20
|
adam@2
|
21 fun pad' len s =
|
adam@2
|
22 if len <= 0 then
|
adam@2
|
23 s
|
adam@2
|
24 else
|
adam@2
|
25 pad' (len-1) ("0" ^ s)
|
adam@2
|
26 in
|
adam@2
|
27 pad' (len - String.length s) s
|
adam@2
|
28 end
|
adam@2
|
29
|
adam@2
|
30 fun monthLen m =
|
adam@2
|
31 let
|
adam@2
|
32 fun f n tm =
|
adam@2
|
33 let
|
adam@2
|
34 val next = addSeconds tm (60 * 60 * 24)
|
adam@2
|
35 val nextMon = readError (timef "%m" next)
|
adam@2
|
36 in
|
adam@2
|
37 if nextMon = m.Month then
|
adam@2
|
38 f (n+1) next
|
adam@2
|
39 else
|
adam@2
|
40 n
|
adam@2
|
41 end
|
adam@2
|
42 in
|
adam@2
|
43 f 28 (readError (show m.Year ^ "-" ^ pad 2 m.Month ^ "-28 00:00:00"))
|
adam@2
|
44 end
|
adam@2
|
45
|
adam@2
|
46 fun weekdayToNum s =
|
adam@2
|
47 case s of
|
adam@2
|
48 "Mon" => 0
|
adam@2
|
49 | "Tue" => 1
|
adam@2
|
50 | "Wed" => 2
|
adam@2
|
51 | "Thu" => 3
|
adam@2
|
52 | "Fri" => 4
|
adam@2
|
53 | "Sat" => 5
|
adam@2
|
54 | "Sun" => 6
|
adam@2
|
55 | _ => error <xml>Datebox: Bad weekday name</xml>
|
adam@2
|
56
|
adam@2
|
57 fun timeOfMonth my =
|
adam@2
|
58 readError (show my.Year ^ "-" ^ pad 2 my.Month ^ "-01 00:00:00")
|
adam@2
|
59
|
adam@2
|
60 fun monthInfo this =
|
adam@2
|
61 let
|
adam@2
|
62 val prev = if this.Month = 1 then
|
adam@2
|
63 {Month = 12, Year = this.Year - 1}
|
adam@2
|
64 else
|
adam@2
|
65 {Month = this.Month-1, Year = this.Year}
|
adam@2
|
66 val prevLen = monthLen prev
|
adam@2
|
67
|
adam@2
|
68 val next = if this.Month = 12 then
|
adam@2
|
69 {Month = 1, Year = this.Year + 1}
|
adam@2
|
70 else
|
adam@2
|
71 {Month = this.Month + 1, Year = this.Year}
|
adam@2
|
72
|
adam@2
|
73 val firstDow = weekdayToNum (timef "%a" (timeOfMonth this))
|
adam@2
|
74 in
|
adam@2
|
75 {ThisMonth = this.Month, Year = this.Year,
|
adam@2
|
76 ThisMonthLength = monthLen this,
|
adam@2
|
77 PrevMonthLength = prevLen,
|
adam@2
|
78 MondayMonth = if firstDow = 0 then This else Prev,
|
adam@2
|
79 MondayDay = if firstDow = 0 then 1 else prevLen - (firstDow - 1),
|
adam@2
|
80 PrevMonthName = timef "%b" (timeOfMonth prev),
|
adam@2
|
81 ThisMonthName = timef "%b" (timeOfMonth this),
|
adam@2
|
82 NextMonthName = timef "%b" (timeOfMonth next)}
|
adam@2
|
83 end
|
adam@2
|
84
|
adam@2
|
85 val create =
|
adam@2
|
86 tm <- now;
|
adam@2
|
87 year <- return (readError (timef "%Y" tm));
|
adam@2
|
88 month <- return (readError (timef "%m" tm));
|
adam@2
|
89 month <- source (monthInfo {Month = month, Year = year});
|
adam@2
|
90 day <- return (readError (timef "%d" tm));
|
adam@2
|
91 day <- source day;
|
adam@2
|
92 return {Month = month, Day = day}
|
adam@2
|
93
|
adam@2
|
94 fun render (t : t) = <xml>
|
adam@2
|
95 <dyn signal={minf <- signal t.Month;
|
adam@2
|
96 let
|
adam@2
|
97 fun rows month day =
|
adam@2
|
98 let
|
adam@2
|
99 fun row month day weekday =
|
adam@2
|
100 if weekday >= 7 then
|
adam@2
|
101 <xml/>
|
adam@2
|
102 else
|
adam@2
|
103 <xml>
|
adam@2
|
104 <td class={case month of
|
adam@2
|
105 This => curday
|
adam@2
|
106 | _ => otherday}>{[day]}</td>
|
adam@2
|
107 {let
|
adam@2
|
108 val (month, day) =
|
adam@2
|
109 case month of
|
adam@2
|
110 Prev => if day = minf.PrevMonthLength then
|
adam@2
|
111 (This, 1)
|
adam@2
|
112 else
|
adam@2
|
113 (Prev, day+1)
|
adam@2
|
114 | This => if day = minf.ThisMonthLength then
|
adam@2
|
115 (Next, 1)
|
adam@2
|
116 else
|
adam@2
|
117 (This, day+1)
|
adam@2
|
118 | Next => (Next, day+1)
|
adam@2
|
119 in
|
adam@2
|
120 row month day (weekday+1)
|
adam@2
|
121 end}
|
adam@2
|
122 </xml>
|
adam@2
|
123 in
|
adam@2
|
124 case month of
|
adam@2
|
125 Next => <xml/>
|
adam@2
|
126 | _ =>
|
adam@2
|
127 <xml>
|
adam@2
|
128 <tr>{row month day 0}</tr>
|
adam@2
|
129 {let
|
adam@2
|
130 val next =
|
adam@2
|
131 case month of
|
adam@2
|
132 Prev => Some (This, day + 7 - minf.PrevMonthLength)
|
adam@2
|
133 | This =>
|
adam@2
|
134 Some (if day + 7 > minf.ThisMonthLength then
|
adam@2
|
135 (Next, day + 7 - minf.ThisMonthLength)
|
adam@2
|
136 else
|
adam@2
|
137 (This, day + 7))
|
adam@2
|
138 | Next => None
|
adam@2
|
139 in
|
adam@2
|
140 case next of
|
adam@2
|
141 None => <xml/>
|
adam@2
|
142 | Some (month, day) => rows month day
|
adam@2
|
143 end}
|
adam@2
|
144 </xml>
|
adam@2
|
145 end
|
adam@2
|
146 in
|
adam@2
|
147 return <xml>
|
adam@2
|
148 <table class={calendar}>
|
adam@2
|
149 <tr>
|
adam@2
|
150 <th class={prev} colspan={2}><< {[minf.PrevMonthName]}</th>
|
adam@2
|
151 <th class={this} colspan={3}>{[minf.ThisMonthName]}</th>
|
adam@2
|
152 <th class={next} colspan={2}>{[minf.NextMonthName]} >></th>
|
adam@2
|
153 </tr>
|
adam@2
|
154 <tr class={weekday}> <th>M</th> <th>Tu</th> <th>W</th> <th>Th</th> <th>F</th> <th>Sa</th> <th>Su</th> </tr>
|
adam@2
|
155 {rows minf.MondayMonth minf.MondayDay}
|
adam@2
|
156 </table>
|
adam@2
|
157 </xml>
|
adam@2
|
158 end}/>
|
adam@2
|
159 </xml>
|
adam@2
|
160
|
adam@2
|
161 fun value t =
|
adam@2
|
162 month <- signal t.Month;
|
adam@2
|
163 day <- signal t.Day;
|
adam@2
|
164 return (readError (show month.Year ^ "-" ^ pad 2 month.ThisMonth ^ "-" ^ pad 2 day ^ " 00:00:00"))
|