forked from mirrors/gecko-dev
		
	 0773795931
			
		
	
	
		0773795931
		
	
	
	
	
		
			
			# ignore-this-changeset Differential Revision: https://phabricator.services.mozilla.com/D36053 --HG-- extra : source : 651d8f947a29f5d80b7e833f7e6b99e2afe8bf9d
		
			
				
	
	
		
			170 lines
		
	
	
	
		
			4.7 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			170 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);
 | |
|   },
 | |
| };
 |