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@3
|
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@3
|
85 fun monthInfo this = return (monthInfo' this)
|
adam@3
|
86
|
adam@2
|
87 val create =
|
adam@2
|
88 tm <- now;
|
adam@2
|
89 year <- return (readError (timef "%Y" tm));
|
adam@2
|
90 month <- return (readError (timef "%m" tm));
|
adam@3
|
91 month <- source (monthInfo' {Month = month, Year = year});
|
adam@2
|
92 day <- return (readError (timef "%d" tm));
|
adam@2
|
93 day <- source day;
|
adam@2
|
94 return {Month = month, Day = day}
|
adam@2
|
95
|
adam@2
|
96 fun render (t : t) = <xml>
|
adam@2
|
97 <dyn signal={minf <- signal t.Month;
|
adam@2
|
98 let
|
adam@2
|
99 fun rows month day =
|
adam@2
|
100 let
|
adam@2
|
101 fun row month day weekday =
|
adam@2
|
102 if weekday >= 7 then
|
adam@2
|
103 <xml/>
|
adam@2
|
104 else
|
adam@2
|
105 <xml>
|
adam@2
|
106 <td class={case month of
|
adam@2
|
107 This => curday
|
adam@2
|
108 | _ => otherday}>{[day]}</td>
|
adam@2
|
109 {let
|
adam@2
|
110 val (month, day) =
|
adam@2
|
111 case month of
|
adam@2
|
112 Prev => if day = minf.PrevMonthLength then
|
adam@2
|
113 (This, 1)
|
adam@2
|
114 else
|
adam@2
|
115 (Prev, day+1)
|
adam@2
|
116 | This => if day = minf.ThisMonthLength then
|
adam@2
|
117 (Next, 1)
|
adam@2
|
118 else
|
adam@2
|
119 (This, day+1)
|
adam@2
|
120 | Next => (Next, day+1)
|
adam@2
|
121 in
|
adam@2
|
122 row month day (weekday+1)
|
adam@2
|
123 end}
|
adam@2
|
124 </xml>
|
adam@2
|
125 in
|
adam@2
|
126 case month of
|
adam@2
|
127 Next => <xml/>
|
adam@2
|
128 | _ =>
|
adam@2
|
129 <xml>
|
adam@2
|
130 <tr>{row month day 0}</tr>
|
adam@2
|
131 {let
|
adam@2
|
132 val next =
|
adam@2
|
133 case month of
|
adam@2
|
134 Prev => Some (This, day + 7 - minf.PrevMonthLength)
|
adam@2
|
135 | This =>
|
adam@2
|
136 Some (if day + 7 > minf.ThisMonthLength then
|
adam@2
|
137 (Next, day + 7 - minf.ThisMonthLength)
|
adam@2
|
138 else
|
adam@2
|
139 (This, day + 7))
|
adam@2
|
140 | Next => None
|
adam@2
|
141 in
|
adam@2
|
142 case next of
|
adam@2
|
143 None => <xml/>
|
adam@2
|
144 | Some (month, day) => rows month day
|
adam@2
|
145 end}
|
adam@2
|
146 </xml>
|
adam@2
|
147 end
|
adam@2
|
148 in
|
adam@2
|
149 return <xml>
|
adam@2
|
150 <table class={calendar}>
|
adam@2
|
151 <tr>
|
adam@3
|
152 <th class={prev} colspan={2}
|
adam@3
|
153 onclick={minf <- rpc (monthInfo (if minf.ThisMonth = 1 then
|
adam@3
|
154 {Month = 12, Year = minf.Year - 1}
|
adam@3
|
155 else
|
adam@3
|
156 {Month = minf.ThisMonth - 1, Year = minf.Year}));
|
adam@3
|
157 set t.Day 1;
|
adam@3
|
158 set t.Month minf}><< {[minf.PrevMonthName]}</th>
|
adam@3
|
159 <th class={this} colspan={3}>{[minf.ThisMonthName]} {[minf.Year]}</th>
|
adam@3
|
160 <th class={next} colspan={2}
|
adam@3
|
161 onclick={minf <- rpc (monthInfo (if minf.ThisMonth = 12 then
|
adam@3
|
162 {Month = 1, Year = minf.Year + 1}
|
adam@3
|
163 else
|
adam@3
|
164 {Month = minf.ThisMonth + 1, Year = minf.Year}));
|
adam@3
|
165 set t.Day 1;
|
adam@3
|
166 set t.Month minf}>{[minf.NextMonthName]} >></th>
|
adam@2
|
167 </tr>
|
adam@2
|
168 <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
|
169 {rows minf.MondayMonth minf.MondayDay}
|
adam@2
|
170 </table>
|
adam@2
|
171 </xml>
|
adam@2
|
172 end}/>
|
adam@2
|
173 </xml>
|
adam@2
|
174
|
adam@2
|
175 fun value t =
|
adam@2
|
176 month <- signal t.Month;
|
adam@2
|
177 day <- signal t.Day;
|
adam@3
|
178 return {Year = month.Year, Month = month.ThisMonth, Day = day}
|