html_cal.py
'''\
HTML TABLE Calendar class.
classes:
html_cal <<object>>
.dotw - "Sun", "Mon",..
.days - "Sunday", "Monday",..
.curr_dt()
.curr_weekday()
functions:
make_web_calendar (props)
Developer@Sonnack.com
April 2016
'''
from sys import stdin, stdout, stderr, argv
from os import path
from datetime import date, datetime, timedelta
from htmlpage import htmlpage
DefaultProperties = {
'year':2000,
'filename': '%04d.html',
'title': 'Calendar',
'h1' : 'Sonnack.com',
'h2' : 'Publications',
'css': ['/basic.css','calendar.css'],
'js' : None,
'cb:year' : lambda x: x.dt1.strftime('%Y'),
'cb:month': lambda x: x.dt1.strftime('%b'),
'cb:day' : lambda x: x.dt1.strftime('%d'),
'cb:prev' : None,
'cb:next' : None,
}
class html_cal (object):
'''\
HTML TABLE Calender class.
Emits an HTML <TABLE> version of a calender.
'''
dotw = ['Sun','Mon','Tue','Wed','Thu','Fri','Sat']
days = ['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday']
def __init__ (self, yr):
self.dt0 = date(yr, 1, 1)
self.dt1 = date(yr, 1, 1)
self.fmt = '%Y'
self.one_day = timedelta(1)
self.cal_head = '<th colspan="3">%d days</th>' % len(self)
self.cal_foot = '<th colspan="3">© cjsonnack</th>'
self.month_head = reduce(lambda acc,n: '%s<th>%s</th>' % (acc,self.dotw[n]), range(7), '')
self.month_foot = self.month_head
self.properties = {'caption':str(self.dt0.year), 'cb:day':None,'cb:month':None,'cb:year':None, 'cb:prev':None,'cb:next':None}
def curr_dt (self):
return self.dt1
def curr_weekday (self):
'''Returns {Su=0,M=1,Tu=2,W=3,Th=4,F=5,Sa=6} on cursor date.'''
return ((self.dt1.weekday() + 1) % 7)
def writepage (self, fp):
cap = self._callback_year(self.properties['caption'])
cb_prev = self.properties['cb:prev']
cb_next = self.properties['cb:next']
ht_prev = cb_prev(self.dt0.year - 1) if cb_prev else ''
ht_next = cb_next(self.dt0.year + 1) if cb_next else ''
print >> fp
print >> fp, '<table class="CalendarBody">'
print >> fp, '<caption>%s%s%s</caption>' % (ht_prev, cap, ht_next)
print >> fp, '<thead><tr>%s</tr></thead>' % self.cal_head
print >> fp, '<tfoot><tr>%s</tr></tfoot>' % self.cal_foot
self._write_body(fp)
print >> fp, '</table>'
print >> fp
def _write_body (self, fp):
print >> fp, '<tbody>'
for row in [0, 3, 6, 9]:
print >> fp, '<tr>'
for col in [1, 2, 3]:
print >> fp, '<td>'
self._write_month(fp, row+col)
print >> fp, '</td>'
print >> fp, '</tr>'
print >> fp, '<tr><th colspan="3"> </th></tr>'
print >> fp, '</tbody>'
def _write_month (self, fp, m):
self.dt1 = date(self.dt0.year, m, 1)
cap = self._callback_month(self.dt1.strftime('%B'))
print >> fp, '<table class="CalendarMonth">'
print >> fp, '<caption>%s</caption>' % cap
print >> fp, '<thead><tr>%s</tr></thead>' % self.month_head
print >> fp, '<tfoot><tr>%s</tr></tfoot>' % self.month_foot
self._month_body(fp, m)
print >> fp, '</table>'
print >> fp
def _month_body (self, fp, m):
start_day = self.curr_weekday()
start_flag = False
print >> fp, '<tbody>'
for row in range(6):
print >> fp, '<tr>'
for d in range(7):
if start_flag:
if m == self.dt1.month:
self._month_day(fp)
else:
print >> fp, '<td> </td>'
else:
if d < start_day:
print >> fp, '<td> </td>'
else:
start_flag = True
self._month_day(fp)
print >> fp, '</tr>'
print >> fp, '</tbody>'
def _month_day (self, fp):
cls = self.days[self.curr_weekday()]
txt = self._callback_day(str(self.dt1.day))
print >> fp, '<td class="%s">%s</td>' % (cls, txt)
self.dt1 = self.dt1 + self.one_day
def _callback_year (self, s):
if 'cb:year' in self.properties:
cb = self.properties['cb:year']
if cb:
try:
return cb(self)
except Exception as e:
print >> stderr, e
return s
def _callback_month (self, s):
if 'cb:month' in self.properties:
cb = self.properties['cb:month']
if cb:
try:
return cb(self)
except Exception as e:
print >> stderr, e
return s
def _callback_day (self, s):
if 'cb:day' in self.properties:
cb = self.properties['cb:day']
if cb:
try:
return cb(self)
except Exception as e:
print >> stderr, e
return s
def __len__ (self):
'''Returns number of days in the year.'''
this_year = date(self.dt0.year , 1, 1)
next_year = date(self.dt0.year+1, 1, 1)
td = next_year - this_year
return td.days
def __str__ (self):
return self.dt0.strftime(self.fmt)
def __repr__ (self):
s = '{html_cal:{date:%s, format:%s}}'
t = (self.dt0, self.fmt)
return s % t
class html_cal_pw (object):
def __init__ (self, cal):
self.cal = cal
def writepage (self, fp):
print >> fp
self.cal.writepage(fp)
print >> fp
def make_web_calendar (props):
'''\
Make Web Calendar.
input properties:
year - calendar year
filename - filename (requires embedded %s or %d)
title h1, h2 - HTML Title and H1 & H2 banner
css, js - HTML CSS & Javascript links
cb:year - callback function to print calendar Year
cb:month - callback function to print calendar Month
cb:day - callback function to print calendar Date
cb:prev - callback function to print "previous year" link
cb:next - callback function to print "next year" link
returns:
[calendar-object, "file-name"]
'''
cal = html_cal(props['year'])
cal.properties['cb:year'] = props['cb:year']
cal.properties['cb:month'] = props['cb:month']
cal.properties['cb:day'] = props['cb:day']
cal.properties['cb:prev'] = props['cb:prev']
cal.properties['cb:next'] = props['cb:next']
filename = props['filename'] % props['year']
fp = open(filename, 'w')
try:
ttl = props['title']
hdr1 = props['h1']
hdr2 = props['h2']
css = props['css']
pg = htmlpage(ttl, h1=hdr1, h2=hdr2, csspages=css)
pg.writepage(fp, html_cal_pw(cal))
print 'wrote: %s' % filename
except:
raise
finally:
fp.close()
return [cal, filename]
def do_test (*args):
print 'test/parameters: %d' % len(args)
DefaultProperties['year'] = 1955
return make_web_calendar(DefaultProperties)
def do_demo (*args):
print 'demo/parameters: %d' % len(args)
a = []
for yr in range(2000, 2017):
DefaultProperties['year'] = yr
g = make_web_calendar(DefaultProperties)
a.append(g[1])
return a
def do_main (*args):
print 'main/parameters: %d' % len(args)
yr = int(args[0]) if 0 < len(args) else 2017
DefaultProperties['year'] = yr
return make_web_calendar(DefaultProperties)
def dispatch (cmd, *args):
print 'command: %s' % cmd
print 'arguments: %d' % len(args)
if cmd == 'test': return do_test(*args)
if cmd == 'demo': return do_demo(*args)
if cmd == 'main': return do_main(*args)
return [None, cmd, args]
if __name__ == '__main__':
print 'autorun: %s' % argv[0]
cmd = argv[1] if 1 < len(argv) else 'test'
etc = argv[2:]
obj = dispatch(cmd, *etc)
print ''
print 'exit/type: %s (length: %d)' % (type(obj), len(obj))
'''eof'''