From 5e91f60d476108b89d1a4babf07a78eaa9997ffb Mon Sep 17 00:00:00 2001 From: frankfang Date: Mon, 24 Apr 2017 15:07:27 +0800 Subject: [PATCH] add Calendar and Date2 --- demos/calendar.html | 66 +++++++++++++++++++ demos/date2.html | 46 +++++++++++++ lib/calendar/index.js | 150 ++++++++++++++++++++++++++++++++++++++++++ lib/date2/index.js | 85 ++++++++++++++++++++++++ lib/dom/index.js | 37 ++++++++++- 5 files changed, 382 insertions(+), 2 deletions(-) create mode 100644 demos/calendar.html create mode 100644 demos/date2.html create mode 100644 lib/calendar/index.js create mode 100644 lib/date2/index.js 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 }, }