diff --git a/demos/calendar.html b/demos/calendar.html
new file mode 100644
index 0000000..2b08917
--- /dev/null
+++ b/demos/calendar.html
@@ -0,0 +1,66 @@
+
+
+
+
+
Calendar
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/demos/date2.html b/demos/date2.html
new file mode 100644
index 0000000..a970ada
--- /dev/null
+++ b/demos/date2.html
@@ -0,0 +1,46 @@
+
+
+
+
+ Date2
+
+
+
+
+
+
+
+
diff --git a/lib/calendar/index.js b/lib/calendar/index.js
new file mode 100644
index 0000000..785bcec
--- /dev/null
+++ b/lib/calendar/index.js
@@ -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: `
+
+
+ 日
+
+
+ `,
+ 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(`${text}`)
+ if ([0, 6].indexOf(n) >= 0) {
+ li.classList.add('weekend')
+ }
+ return li
+ })
+ return dom.create(`
`, 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(`
`, 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
+ }
+}
diff --git a/lib/date2/index.js b/lib/date2/index.js
new file mode 100644
index 0000000..55a804e
--- /dev/null
+++ b/lib/date2/index.js
@@ -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
+}
diff --git a/lib/dom/index.js b/lib/dom/index.js
index 33dfdd5..c26116e 100644
--- a/lib/dom/index.js
+++ b/lib/dom/index.js
@@ -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
},
}