Skip to content

Commit

Permalink
add Calendar and Date2
Browse files Browse the repository at this point in the history
  • Loading branch information
FrankFang committed Apr 24, 2017
1 parent e81cc49 commit 5e91f60
Show file tree
Hide file tree
Showing 5 changed files with 382 additions and 2 deletions.
66 changes: 66 additions & 0 deletions demos/calendar.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
<!DOCTYPE html>
<html lang="zh-Hans">
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<title>Calendar</title>

<div class="page">
<nav>
<h1 class="date"></h1>
<div class="controls">
<button id="previousMonth">&lt;</button>
<button id="today">今天</button>
<button id="nextMonth">&gt;</button>
</div>
</nav>
<div class="calendar"></div>
</div>
<script src="../lib/dom/index.js"></script>
<script src="../lib/date2/index.js"></script>
<script src="../lib/calendar/index.js"></script>
<style>
body{margin:0;}
* {box-sizing: border-box;}
h1{margin: 0;}
.page{ min-height: 100vh; display: flex; flex-direction: column; }
.page > nav:first-child{text-align: right; display: flex;
justify-content: space-between; align-items: center;padding: 1em;}
.calendar { flex-grow: 1; display: flex; flex-direction: column;}
.calendar> ol{list-style:none; margin:0; padding:0; }
.calendar> ol.weekdays{display: flex; text-align: right; }
.calendar> ol.weekdays >li{width: 14.2857%; padding: .5em 1em;}

.calendar> ol.days{display: flex; flex-wrap: wrap; flex-grow: 1;}
.calendar> ol.days>li{width: 14.2857%; border-right: 1px solid #C7C7CC; border-top: 1px solid #C7C7CC;
position: relative;
}
.calendar> ol.days>li:nth-child(7n){ border-right: none; }
.calendar> ol.days>li> .dayLabel{
position: absolute; right: 1em; top: .8em; white-space: nowrap; text-align: right;
}

.calendar .today .day{ background: red; width: 1.6em; display: inline-block; text-align: center; height: 1.6em;
line-height: 1.6em; border-radius: 50%; color: white;
}
.calendar .weekdays .weekend{ color: #B8B8B8; }
.calendar .days .weekend{ background: #F5F5F5; }
</style>
<script>
let calendar = new Calendar({
element: document.querySelector('.calendar'),
output: document.querySelector('.date'),
})
previousMonth.onclick = function(){
calendar.previousMonth()
}
nextMonth.onclick = function(){
calendar.nextMonth()
}
today.onclick = function(){
calendar.resetMonth()
}
</script>

<!--百度统计-->
<script> var _hmt = _hmt || []; (function() { var hm = document.createElement("script"); hm.src = "https://hm.baidu.com/hm.js?950926001a84a4f88cd3e1c7c0bfac08"; var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(hm, s); })(); </script>
</html>
46 changes: 46 additions & 0 deletions demos/date2.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<!DOCTYPE html>
<html lang="zh-Hans">
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<title>Date2</title>

<div class="calendar"></div>
<script src="../lib/date2/index.js"></script>
<script>
{
let assert = console.assert.bind(console)
let date = new Date(2011, 0, 4, 6, 8, 10, 999)
let d1 = new Date2(date)
assert(d1.date !== date)
assert(d1.date.getTime() === date.getTime())

assert(d1.weekday() === date.getDay())
assert(d1.day() === date.getDate())
assert(d1.year() === date.getFullYear())
assert(d1.month() === date.getMonth() + 1)
assert(d1.hours() === date.getHours())
assert(d1.minutes() === date.getMinutes())
assert(d1.seconds() === date.getSeconds())
assert(d1.milliseconds() === date.getMilliseconds())
assert(d1.year(2012).date.getFullYear() === 2012)
assert(date.getFullYear() === 2011)
assert(d1.month(4).date.getMonth() === 3)
assert(d1.day(1).date.getDate() === 1)
assert(d1.hours(2).date.getHours() === 2)
assert(d1.minutes(2).date.getMinutes() === 2)
assert(d1.seconds(2).date.getSeconds() === 2)
assert(d1.milliseconds(2).date.getMilliseconds() === 2)

assert(d1.monthBeginning.day() === 1)
assert(d1.monthEnding.day() === 31)

let d2 = new Date2(new Date(2011,0,31))
assert(d2.nextMonth.month() === 2)
assert(d2.nextMonth.nextMonth.month() === 3)
}

</script>

<!--百度统计-->
<script> var _hmt = _hmt || []; (function() { var hm = document.createElement("script"); hm.src = "https://hm.baidu.com/hm.js?950926001a84a4f88cd3e1c7c0bfac08"; var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(hm, s); })(); </script>
</html>
150 changes: 150 additions & 0 deletions lib/calendar/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
{
class Calendar {
constructor(options) {
let defaultOptions = {
element: null,
startOfWeek: 1, // 1 or 0
strings: {
weekdays: n => {
let map = { 0: '周日', 1: '周一', 2: '周二', 3: '周三', 4: '周四', 5: '周五', 6: '周六' }
return map[n]
},
days: n => `${n}`,
dayTemplate: `
<li>
<span class="dayLabel">
<span class="day"></span><span class="unit">日</span>
</span>
</li>
`,
output: d => `${d.getFullYear()}${d.getMonth() + 1}月`,
},
}

this.options = Object.assign({}, defaultOptions, options)
this.currentDate = new Date()
this._checkOptions()
this._generateCalendar()
}
nextMonth() {
this.currentDate = new Date2(this.currentDate).nextMonth.date
this._generateCalendar()
}
previousMonth() {
this.currentDate = new Date2(this.currentDate).previousMonth.date
this._generateCalendar()
}
resetMonth() {
this.currentDate = new Date()
this._generateCalendar()
}
_checkOptions() {
if (!this.options.element) {
throw new Error('element is required')
}
return this
}
_generateWeekdays() {
let { startOfWeek, strings } = this.options
let items = createArray({ length: 7, fill: startOfWeek }).map((day, i) => {
let n = day + i >= 7 ? day + i - 7 : day + i
let text = strings.weekdays(n)
let li = dom.create(`<li>${text}</li>`)
if ([0, 6].indexOf(n) >= 0) {
li.classList.add('weekend')
}
return li
})
return dom.create(`<ol class="weekdays"></ol>`, items)
}
_generateCurrentMonth() {
let current = new Date2(this.currentDate)
let dayCount = current.monthEnding.day()
let convert = this.options.strings.days
return createArray({ length: dayCount }).map((_, i) => {
let date2 = current.day(i + 1)
let li = dom.create(this.options.strings.dayTemplate)
li.className = 'currentMonth'
if (date2.isSameDayAs(new Date())) {
li.classList.add('today')
}
if ([0, 6].indexOf(date2.weekday()) >= 0) {
li.classList.add('weekend')
}
li.querySelector('.day').textContent = convert(i + 1)
return li
})
}
_generatePreviousMonth() {
let { startOfWeek } = this.options
let date2 = new Date2(this.currentDate)
let monthBeginning = date2.monthBeginning
let startPadding = monthBeginning.weekday() >= startOfWeek
? monthBeginning.weekday() - startOfWeek
: monthBeginning.weekday() + 7 - startOfWeek
let convert = this.options.strings.days
return createArray({ length: startPadding })
.map((_, i) => {
let li = dom.create(this.options.strings.dayTemplate)
li.className = 'previousMonth'
if ([0, 6].indexOf(date2.day(-i).weekday()) >= 0) {
li.classList.add('weekend')
}
li.querySelector('.day').textContent = convert(date2.day(-i).day())
return li
})
.reverse()
}
_generateNextMonth() {
let { startOfWeek } = this.options
let date2 = new Date2(this.currentDate)
let monthEnding = date2.monthEnding
let endPadding = monthEnding.weekday() >= startOfWeek
? 7 - (monthEnding.weekday() - startOfWeek + 1)
: 7 - (monthEnding.weekday() + 7 - startOfWeek + 1)
let convert = this.options.strings.days

return createArray({ length: endPadding }).map((_, i) => {
let li = dom.create(this.options.strings.dayTemplate)
li.className = 'nextMonth'
let data2 = new Date2(this.currentDate)
if ([0, 6].indexOf(date2.nextMonth.day(i + 1).weekday()) >= 0) {
li.classList.add('weekend')
}
li.querySelector('.day').textContent = convert(i + 1)
return li
})
}
_generateDays() {
let { startOfWeek } = this.options
let date2 = new Date2(this.currentDate)
let monthBeginning = date2.monthBeginning
let monthEnding = date2.monthEnding

let days = this._generateCurrentMonth()
days = this._generatePreviousMonth().concat(days)
days = days.concat(this._generateNextMonth())
return dom.create(`<ol class=days></ol>`, days)
}
_generateCalendar() {
let { element } = this.options
dom.removeChildren(element)
dom.append(element, this._generateWeekdays())
dom.append(element, this._generateDays())
this.options.output.textContent = this.options.strings.output(this.currentDate)
return this
}
}

window.Calendar = Calendar

// 生成一个长度位 length,内容为 fill 的数组
// 不同于 new Array(length),createArray 生成的数组是有 0 到 length 下标的
function createArray({ length, fill }) {
let array = Array.apply(null, { length: length })
if (fill !== undefined) {
array = array.map(() => fill)
}
return array
}
}
85 changes: 85 additions & 0 deletions lib/date2/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
{
class Date2 {
constructor(date = new Date()) {
this.date = new Date(date - 0)
}
weekday(n) {
if (n) {
throw new Error('You can not set weekday')
}
return this._proxy('day')
}
day(n) {
return this._proxy('date', n)
}
year(n) {
return this._proxy('fullYear', n)
}
month(n) {
return this._proxy('month', n, 1)
}
get monthBeginning() {
return this.day(1)
}
get monthEnding() {
return this.month(this.month() + 1).day(0)
}
get nextMonth() {
let day = this.day()
let month = this.month()
let nextMonth = this.day(1).month(month + 1)
if (day > nextMonth.monthEnding.day()) {
return nextMonth.monthEnding
} else {
return nextMonth.day(day)
}
}
get previousMonth() {
let day = this.day()
let month = this.month()
let nextMonth = this.day(1).month(month - 1)
if (day > nextMonth.monthEnding.day()) {
return nextMonth.monthEnding
} else {
return nextMonth.day(day)
}
}
hours(n) {
return this._proxy('hours', n)
}
minutes(n) {
return this._proxy('minutes', n)
}
seconds(n) {
return this._proxy('seconds', n)
}
milliseconds(n) {
return this._proxy('milliseconds', n)
}
get clone() {
return new Date2(this.date)
}

_proxy(name, n, offset = 0) {
if (n === undefined) {
return this.date[`get${capitalize(name)}`]() + offset
} else {
let d = this.clone
d.date[`set${capitalize(name)}`](n - offset)
return d
}
}
isSameMonthAs(date) {
return this.year() === date.getFullYear() && this.month() === date.getMonth() + 1
}
isSameDayAs(date) {
return this.isSameMonthAs(date) && this.day() === date.getDate()
}
}

function capitalize(string) {
return string.charAt(0).toUpperCase() + string.slice(1)
}

window.Date2 = Date2
}
37 changes: 35 additions & 2 deletions lib/dom/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,9 +71,42 @@ let dom = {
},

// http://stackoverflow.com/a/35385518/1262580
create: function(html) {
create: function(html, children) {
var template = document.createElement('template')
template.innerHTML = html.trim()
return template.content.firstChild
let node = template.content.firstChild
if (children) {
dom.append(node, children)
}
return node
},

append: function(parent, children) {
if (children.length === undefined) {
children = [children]
}
for (let i = 0; i < children.length; i++) {
parent.appendChild(children[i])
}
return parent
},
prepend: function(parent, children) {
if (children.length === undefined) {
children = [children]
}
for (let i = children.length - 1; i >= 0; i--) {
if (parent.firstChild) {
parent.insertBefore(children[i], parent.firstChild)
} else {
parent.appendChild(children[i])
}
}
return parent
},
removeChildren: function(element) {
while (element.hasChildNodes()) {
element.removeChild(element.lastChild)
}
return this
},
}

0 comments on commit 5e91f60

Please sign in to comment.