Backed out changeset d3c9e777a050 (bug 1676068) Backed out changeset 639c9661c850 (bug 1676068) Backed out changeset d06b6aa3b9a3 (bug 1676068) Backed out changeset 50bb7e9c6bcf (bug 1676068) Backed out changeset 234acd14548e (bug 1676068) Backed out changeset 04050cfd5e3f (bug 1676068) Backed out changeset a06081c85646 (bug 1676068)
171 lines
4.7 KiB
JavaScript
171 lines
4.7 KiB
JavaScript
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
"use strict";
|
|
|
|
/**
|
|
* Initialize the Calendar and generate nodes for week headers and days, and
|
|
* attach event listeners.
|
|
*
|
|
* @param {Object} options
|
|
* {
|
|
* {Number} calViewSize: Number of days to appear on a calendar view
|
|
* {Function} getDayString: Transform day number to string
|
|
* {Function} getWeekHeaderString: Transform day of week number to string
|
|
* {Function} setSelection: Set selection for dateKeeper
|
|
* }
|
|
* @param {Object} context
|
|
* {
|
|
* {DOMElement} weekHeader
|
|
* {DOMElement} daysView
|
|
* }
|
|
*/
|
|
function Calendar(options, context) {
|
|
const DAYS_IN_A_WEEK = 7;
|
|
|
|
this.context = context;
|
|
this.state = {
|
|
days: [],
|
|
weekHeaders: [],
|
|
setSelection: options.setSelection,
|
|
getDayString: options.getDayString,
|
|
getWeekHeaderString: options.getWeekHeaderString,
|
|
};
|
|
this.elements = {
|
|
weekHeaders: this._generateNodes(DAYS_IN_A_WEEK, context.weekHeader),
|
|
daysView: this._generateNodes(options.calViewSize, context.daysView),
|
|
};
|
|
|
|
this._attachEventListeners();
|
|
}
|
|
|
|
Calendar.prototype = {
|
|
/**
|
|
* Set new properties and render them.
|
|
*
|
|
* @param {Object} props
|
|
* {
|
|
* {Boolean} isVisible: Whether or not the calendar is in view
|
|
* {Array<Object>} days: Data for days
|
|
* {
|
|
* {Date} dateObj
|
|
* {Number} content
|
|
* {Array<String>} classNames
|
|
* {Boolean} enabled
|
|
* }
|
|
* {Array<Object>} weekHeaders: Data for weekHeaders
|
|
* {
|
|
* {Number} content
|
|
* {Array<String>} classNames
|
|
* }
|
|
* }
|
|
*/
|
|
setProps(props) {
|
|
if (props.isVisible) {
|
|
// Transform the days and weekHeaders array for rendering
|
|
const days = props.days.map(
|
|
({ dateObj, content, classNames, enabled }) => {
|
|
return {
|
|
dateObj,
|
|
textContent: this.state.getDayString(content),
|
|
className: classNames.join(" "),
|
|
enabled,
|
|
};
|
|
}
|
|
);
|
|
const weekHeaders = props.weekHeaders.map(({ content, classNames }) => {
|
|
return {
|
|
textContent: this.state.getWeekHeaderString(content),
|
|
className: classNames.join(" "),
|
|
};
|
|
});
|
|
// Update the DOM nodes states
|
|
this._render({
|
|
elements: this.elements.daysView,
|
|
items: days,
|
|
prevState: this.state.days,
|
|
});
|
|
this._render({
|
|
elements: this.elements.weekHeaders,
|
|
items: weekHeaders,
|
|
prevState: this.state.weekHeaders,
|
|
});
|
|
// Update the state to current
|
|
this.state.days = days;
|
|
this.state.weekHeaders = weekHeaders;
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Render the items onto the DOM nodes
|
|
* @param {Object}
|
|
* {
|
|
* {Array<DOMElement>} elements
|
|
* {Array<Object>} items
|
|
* {Array<Object>} prevState: state of items from last render
|
|
* }
|
|
*/
|
|
_render({ elements, items, prevState }) {
|
|
for (let i = 0, l = items.length; i < l; i++) {
|
|
let el = elements[i];
|
|
|
|
// Check if state from last render has changed, if so, update the elements
|
|
if (!prevState[i] || prevState[i].textContent != items[i].textContent) {
|
|
el.textContent = items[i].textContent;
|
|
}
|
|
if (!prevState[i] || prevState[i].className != items[i].className) {
|
|
el.className = items[i].className;
|
|
}
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Generate DOM nodes
|
|
*
|
|
* @param {Number} size: Number of nodes to generate
|
|
* @param {DOMElement} context: Element to append the nodes to
|
|
* @return {Array<DOMElement>}
|
|
*/
|
|
_generateNodes(size, context) {
|
|
let frag = document.createDocumentFragment();
|
|
let refs = [];
|
|
|
|
for (let i = 0; i < size; i++) {
|
|
let el = document.createElement("div");
|
|
el.dataset.id = i;
|
|
refs.push(el);
|
|
frag.appendChild(el);
|
|
}
|
|
context.appendChild(frag);
|
|
|
|
return refs;
|
|
},
|
|
|
|
/**
|
|
* Handle events
|
|
* @param {DOMEvent} event
|
|
*/
|
|
handleEvent(event) {
|
|
switch (event.type) {
|
|
case "click": {
|
|
if (event.target.parentNode == this.context.daysView) {
|
|
let targetId = event.target.dataset.id;
|
|
let targetObj = this.state.days[targetId];
|
|
if (targetObj.enabled) {
|
|
this.state.setSelection(targetObj.dateObj);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Attach event listener to daysView
|
|
*/
|
|
_attachEventListeners() {
|
|
this.context.daysView.addEventListener("click", this);
|
|
},
|
|
};
|