javascript
1 < ! DOCTYPE html >
2 < html lang = "ja" >
3 < meta charset = "utf-8" >
4 < style >
5 #calendar td { text - align : center ; font - size : 80 % ; }
6 #calendar . sun { background : rgba ( 255 , 0 , 0 , .1 ) ; color : rgba ( 255 , 0 , 0 , 1 ) ; }
7 #calendar . sat { background : rgba ( 0 , 0 , 255 , .1 ) ; color : rgba ( 0 , 0 , 255 , 1 ) ; }
8 #calendar . button { color : blue ; text - decoration : underline ; }
9 #calendar . button : hover { color : red ; }
10 #calendar table , #calendar td { border : 1 px gray solid ; padding : 4 px ; }
11 #calendar table { border - collapse : collapse ; border - spacing : 0 ; }
12 #calendar tbody tr : nth - of - type ( odd ) { background : rgba ( 0 , 0 , 0 , .05 ) ; }
13 < / style >
14
15 < body >
16 < div id = "calendar" > < / div >
17 < input type = "text" class = "text" id = "acdn-target" onselect = "click_date" readonly >
18
19
20
21 < script >
22 {
23 const
24 day_name = [ 'sun' , 'mon' , 'tue' , 'wed' , 'thu' , 'fri' , 'sat' ] ,
25 day_jname = [ '(Sun.)' , '(Mon.)' , '(Tue.)' , '(Wed.)' , '(Thurs.)' , '(Fri.)' , '(Sat.)' ] ,
26 doc = document ,
27 DEF_OPTION = { } ;
28
29 const
30 A = ( e , ... a ) => a . map ( a => e . appendChild ( doc . createElement ( a ) ) ) ,
31 B = ( d , n ) => d . setDate ( d . getDate ( ) + n ) ,
32 C = d => [ d . getFullYear ( ) , '年' , d . getMonth ( ) + 1 , '月' ] . join ( '' ) ,
33 D = d => [ ( '0' + d . getHours ( ) ) . slice ( - 2 ) , ( '0' + d . getMinutes ( ) ) . slice ( - 2 ) ] . join ( ':' ) ,
34 E = ( e , d ) => {
35 let
36 [ a , , b ] = A ( e , 'label' , 'br' , 'label' ) ,
37 w = d . getDay ( ) ;
38 a . textContent = d . getDate ( ) ;
39 b . textContent = day_jname [ w ] ;
40 e . classList . add ( day_name [ w ] ) ;
41 } ,
42 F = d => {
43 let m = d . getMonth ( ) ;
44 return [ 0 , 31 , 59 , 90 , 120 , 151 , 181 , 212 , 243 , 273 , 304 , 334 ] [ m ] + d . getDate ( ) - 1 +
45 ( new Date ( d . getFullYear ( ) , m + 1 , 0 ) === 29 && 0 < m ) ;
46 } ,
47 G = ary => ary . reduce ( ( a , b ) => {
48 let
49 c = typeof b === 'string' ? new Date ( b + ':00.000+09:00' ) : b ,
50 d = D ( c ) ;
51 if ( ! ( d in a ) ) a [ d ] = [ ] ;
52 a [ d ] [ F ( c ) ] = true ;
53 return a ;
54 } , { } )
55 ,
56 H = d => new Date ( d . getFullYear ( ) , d . getMonth ( ) , d . getDate ( ) ) ,
57 I = d => [ ( '0' + d . getUTCHours ( ) ) . slice ( - 2 ) , ( '0' + d . getUTCMinutes ( ) ) . slice ( - 2 ) ] . join ( ':' ) ;
58
59
60 //_____________
61
62 class Shedule {
63 constructor ( date = new Date , range = 7 , plan = [ ] , option = DEF_OPTION ) {
64 this . current = H ( date ) ;
65 this . date = H ( date ) ;
66 this . range = range ;
67 this . plan = G ( plan ) ;
68 this . table = document . createElement ( 'table' ) ;
69 this . option = Object . assign ( { } , option ) ;
70
71 this . remake ( ) ;
72 }
73
74
75 add ( day = this . range ) {
76 let d = H ( this . current ) ;
77 d . setDate ( d . getDate ( ) + day ) ;
78 if ( + this . date <= + d ) {
79 this . current = d ;
80 this . remake ( ) ;
81 }
82 }
83
84
85 setHoliday ( dayNo ) {
86 let
87 year = this . current . getFullYear ( ) ,
88 start = new Date ( year , 0 , 1 ) ,
89 end = new Date ( year , 12 , 1 ) ,
90 current = new Date ( start ) ,
91
92 b = new Date ( Date . UTC ( 1970 , 0 , 1 , 9 , 0 ) ) , //列のスタート時間
93 e = new Date ( Date . UTC ( 1970 , 0 , 1 , 11 , 30 ) ) , //列の終了時間
94 s = new Date ( Date . UTC ( 1970 , 0 , 1 , 0 , 30 ) ) ; //列の感覚調整時間
95
96 current . setDate ( 7 - current . getDate ( ) + dayNo ) ;
97
98 for ( ; current < end ; current . setDate ( current . getDate ( ) + 7 ) ) {
99 let idx = F ( current ) ;
100
101 for ( let c = b ; c < e ; c = new Date ( + s + ( + c ) ) ) {
102 let key = I ( c ) ;
103 if ( ! this . plan [ key ] )
104 this . plan [ key ] = [ ] ;
105 this . plan [ key ] [ idx ] = true ;
106 }
107 }
108
109 this . remake ( ) ;
110 }
111
112
113 remake ( ) {
114 this . prev_btn = this . next_btn = null ;
115 let t = this . table ;
116 [ ... t . childNodes ] . forEach ( e => e . remove ( ) ) ;
117
118 let
119 h = t . createTHead ( ) ,
120 tr0 = h . insertRow ( - 1 ) ,
121 tr1 = h . insertRow ( - 1 ) ,
122 d = H ( this . current ) ,
123 s = tr0 . insertCell ( - 1 ) ,
124 c = 1 ,
125 m = d . getMonth ( ) ;
126
127 for ( let i = 0 ; i < this . range ; i ++ , c ++ , B ( d , 1 ) ) {
128 let td = tr1 . insertCell ( - 1 ) ;
129 if ( m !== d . getMonth ( ) ) {
130 s . colSpan = c - 1 ;
131 s = tr0 . insertCell ( - 1 ) ;
132 m = d . getMonth ( ) ;
133 c = 1 ;
134 }
135 s . textContent = C ( d ) ;
136 E ( td , d ) ;
137 }
138 s . colSpan = c - 1 ;
139
140 let e = tr0 . insertCell ( 0 ) ;
141 e . textContent = '前の一週間' ;
142 e . classList . add ( 'button' ) ;
143 e . rowSpan = 2 ;
144 this . prev_btn = e ;
145
146 e = tr0 . insertCell ( - 1 ) ;
147 e . textContent = '次の一週間' ;
148 e . classList . add ( 'button' ) ;
149 e . rowSpan = 2 ;
150 this . next_btn = e ;
151
152 //__
153 let
154 begin = new Date ( Date . UTC ( 1970 , 0 , 1 , 9 , 0 ) ) , //列のスタート時間
155 end = new Date ( Date . UTC ( 1970 , 0 , 1 , 11 , 30 ) ) , //列の終了時間
156 step = new Date ( Date . UTC ( 1970 , 0 , 1 , 0 , 30 ) ) , //列の感覚調整時間
157 o = F ( this . current ) ,
158 rst = [ ] ;
159
160 for ( let d = begin ; d < end ; d = new Date ( + step + ( + d ) ) ) {
161 let
162 a = new Array ( this . rangi ) ,
163 b = I ( d ) ,
164 c = this . plan [ b ] || [ ] ;
165
166 for ( let i = 0 ; i < this . range ; i ++ )
167 a [ i ] = c [ o + i ] ? '-' : '◎' ;
168
169 rst . push ( [ b , ... a , b ] ) ;
170 }
171
172 let [ tb ] = A ( t , 'tbody' ) ;
173 rst . forEach ( r => {
174 let tr = tb . insertRow ( - 1 ) ;
175 r . forEach ( c => tr . insertCell ( - 1 ) . textContent = c )
176 } ) ;
177 }
178
179
180 handleEvent ( event ) {
181 let t = event . target ;
182 if ( t === this . prev_btn ) this . add ( - this . range ) ;
183 if ( t === this . next_btn ) this . add ( this . range ) ;
184
185 let cbfunc = this . option . handleEvent ;
186 if ( 'function' === typeof cbfunc )
187 cbfunc . call ( this , event ) ;
188 }
189
190 }
191
192 this . Shedule = Shedule ;
193 }
194
195 //_____________
196
197 const BUSY = [ '2019-02-12T10:00' ] ;
198
199 function optCallBackFunction ( event ) {
200 const
201 getParent = ( n , e ) => {
202 do { if ( n === e . tagName ) break ; } while ( e = e . parentNode ) ;
203 return e ;
204 } ;
205
206 let
207 td = event . target ;
208 inp = document . querySelector ( "#acdn-target" ) ,
209 tr = this . table . querySelector ( 'thead tr:nth-of-type(2)' ) ,
210 d = new Date ( this . current ) ;
211
212 if ( 'click' === event . type ) {
213 if ( tr . compareDocumentPosition ( td ) & 16 ) {
214 td = getParent ( 'TD' , td ) ;
215 d . setDate ( d . getDate ( ) + td . cellIndex ) ;
216 inp . value = [
217 d . getFullYear ( ) + '年' ,
218 d . getMonth ( ) + 1 + '月' ,
219 d . getDate ( ) + '日で~す'
220 ] . join ( '' ) ;
221 }
222 }
223 }
224
225
226 //_____________
227 let opt = { handleEvent : optCallBackFunction } ;
228 let c = new Shedule ( new Date , 7 , BUSY , opt ) , { table : d } = c ;
229 c . setHoliday ( 1 ) ;
230
231 document . querySelector ( '#calendar' ) . appendChild ( d ) ;
232 d . addEventListener ( 'click' , c , false ) ;
233 d . border = 1 ;
234
235 < / script >