From 8fd370c9f39b4bc1d78cc0f763bf4e99dfd0c382 Mon Sep 17 00:00:00 2001 From: janekptacijarabaci Date: Wed, 14 Feb 2018 12:32:46 +0100 Subject: Bug 1283385: Implement UI for --- toolkit/content/widgets/calendar.js | 172 ++++++++++++++++++++++++++++++++++++ 1 file changed, 172 insertions(+) create mode 100644 toolkit/content/widgets/calendar.js (limited to 'toolkit/content/widgets/calendar.js') diff --git a/toolkit/content/widgets/calendar.js b/toolkit/content/widgets/calendar.js new file mode 100644 index 000000000..72e0d9d61 --- /dev/null +++ b/toolkit/content/widgets/calendar.js @@ -0,0 +1,172 @@ +/* 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 + * } + * @param {Object} context + * { + * {DOMElement} weekHeader + * {DOMElement} daysView + * } + */ +function Calendar(options, context) { + const DAYS_IN_A_WEEK = 7; + + this.context = context; + this.state = { + days: [], + weekHeaders: [] + }; + this.props = {}; + 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} days: Data for days + * { + * {Number} dateValue: Date in milliseconds + * {Number} textContent + * {Array} classNames + * } + * {Array} weekHeaders: Data for weekHeaders + * { + * {Number} textContent + * {Array} classNames + * } + * {Function} getDayString: Transform day number to string + * {Function} getWeekHeaderString: Transform day of week number to string + * {Function} setValue: Set value for dateKeeper + * {Number} selectionValue: The selection date value + * } + */ + setProps(props) { + if (props.isVisible) { + // Transform the days and weekHeaders array for rendering + const days = props.days.map(({ dateValue, textContent, classNames }) => { + return { + dateValue, + textContent: props.getDayString(textContent), + className: dateValue == props.selectionValue ? + classNames.concat("selection").join(" ") : + classNames.join(" ") + }; + }); + const weekHeaders = props.weekHeaders.map(({ textContent, classNames }) => { + return { + textContent: props.getWeekHeaderString(textContent), + 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; + } + + this.props = Object.assign(this.props, props); + }, + + /** + * Render the items onto the DOM nodes + * @param {Object} + * { + * {Array} elements + * {Array} items + * {Array} 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} + */ + _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; + this.props.setValue({ + selectionValue: this.props.days[targetId].dateValue, + dateValue: this.props.days[targetId].dateValue + }); + } + break; + } + } + }, + + /** + * Attach event listener to daysView + */ + _attachEventListeners() { + this.context.daysView.addEventListener("click", this); + } + }; +} -- cgit v1.2.3 From e25430117a67f5c898e5e9388ebd44b185d469ab Mon Sep 17 00:00:00 2001 From: janekptacijarabaci Date: Fri, 30 Mar 2018 12:17:17 +0200 Subject: moebius#92: HTML - input - datetime + native in moebius: Bug 1317600: https://bugzilla.mozilla.org/show_bug.cgi?id=1317600 A note - not implemented: Bug 1282768: https://bugzilla.mozilla.org/show_bug.cgi?id=1282768 *.css: filter: url("chrome://global/skin/filters.svg#fill");, fill: Bug 1283385: https://bugzilla.mozilla.org/show_bug.cgi?id=1283385 Bug 1323109: https://bugzilla.mozilla.org/show_bug.cgi?id=1323109 Bug 1314544: https://bugzilla.mozilla.org/show_bug.cgi?id=1314544 Bug 1286182: https://bugzilla.mozilla.org/show_bug.cgi?id=1286182 Bug 1325922: https://bugzilla.mozilla.org/show_bug.cgi?id=1325922 A note - not implemented: Bug 1282768: https://bugzilla.mozilla.org/show_bug.cgi?id=1282768 *.css: filter: url("chrome://global/skin/filters.svg#fill");, fill: Bug 1320225: https://bugzilla.mozilla.org/show_bug.cgi?id=1320225 Bug 1341190: https://bugzilla.mozilla.org/show_bug.cgi?id=1341190 --- toolkit/content/widgets/calendar.js | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) (limited to 'toolkit/content/widgets/calendar.js') diff --git a/toolkit/content/widgets/calendar.js b/toolkit/content/widgets/calendar.js index 72e0d9d61..80c2976e0 100644 --- a/toolkit/content/widgets/calendar.js +++ b/toolkit/content/widgets/calendar.js @@ -54,23 +54,21 @@ function Calendar(options, context) { * { * {Number} textContent * {Array} classNames + * {Boolean} enabled * } * {Function} getDayString: Transform day number to string * {Function} getWeekHeaderString: Transform day of week number to string - * {Function} setValue: Set value for dateKeeper - * {Number} selectionValue: The selection date value + * {Function} setSelection: Set selection for dateKeeper * } */ setProps(props) { if (props.isVisible) { // Transform the days and weekHeaders array for rendering - const days = props.days.map(({ dateValue, textContent, classNames }) => { + const days = props.days.map(({ dateObj, classNames, enabled }) => { return { - dateValue, - textContent: props.getDayString(textContent), - className: dateValue == props.selectionValue ? - classNames.concat("selection").join(" ") : - classNames.join(" ") + textContent: props.getDayString(dateObj.getUTCDate()), + className: classNames.join(" "), + enabled }; }); const weekHeaders = props.weekHeaders.map(({ textContent, classNames }) => { @@ -152,10 +150,10 @@ function Calendar(options, context) { case "click": { if (event.target.parentNode == this.context.daysView) { let targetId = event.target.dataset.id; - this.props.setValue({ - selectionValue: this.props.days[targetId].dateValue, - dateValue: this.props.days[targetId].dateValue - }); + let targetObj = this.props.days[targetId]; + if (targetObj.enabled) { + this.props.setSelection(targetObj.dateObj); + } } break; } -- cgit v1.2.3 From e14c686ac0ad5e6cfdd933049c11b80a425283dc Mon Sep 17 00:00:00 2001 From: janekptacijarabaci Date: Fri, 30 Mar 2018 23:50:34 +0200 Subject: Bug 1381421 - (Part 1) Handle dates earlier than 0001-01-01 and later than 275760-09-13 correctly --- toolkit/content/widgets/calendar.js | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) (limited to 'toolkit/content/widgets/calendar.js') diff --git a/toolkit/content/widgets/calendar.js b/toolkit/content/widgets/calendar.js index 80c2976e0..44ba67501 100644 --- a/toolkit/content/widgets/calendar.js +++ b/toolkit/content/widgets/calendar.js @@ -11,6 +11,9 @@ * @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 * { @@ -24,9 +27,11 @@ function Calendar(options, context) { this.context = context; this.state = { days: [], - weekHeaders: [] + weekHeaders: [], + setSelection: options.setSelection, + getDayString: options.getDayString, + getWeekHeaderString: options.getWeekHeaderString }; - this.props = {}; this.elements = { weekHeaders: this._generateNodes(DAYS_IN_A_WEEK, context.weekHeader), daysView: this._generateNodes(options.calViewSize, context.daysView) @@ -46,34 +51,32 @@ function Calendar(options, context) { * {Boolean} isVisible: Whether or not the calendar is in view * {Array} days: Data for days * { - * {Number} dateValue: Date in milliseconds - * {Number} textContent + * {Date} dateObj + * {Number} content * {Array} classNames + * {Boolean} enabled * } * {Array} weekHeaders: Data for weekHeaders * { - * {Number} textContent + * {Number} content * {Array} classNames - * {Boolean} enabled * } - * {Function} getDayString: Transform day number to string - * {Function} getWeekHeaderString: Transform day of week number to string - * {Function} setSelection: Set selection for dateKeeper * } */ setProps(props) { if (props.isVisible) { // Transform the days and weekHeaders array for rendering - const days = props.days.map(({ dateObj, classNames, enabled }) => { + const days = props.days.map(({ dateObj, content, classNames, enabled }) => { return { - textContent: props.getDayString(dateObj.getUTCDate()), + dateObj, + textContent: this.state.getDayString(content), className: classNames.join(" "), enabled }; }); - const weekHeaders = props.weekHeaders.map(({ textContent, classNames }) => { + const weekHeaders = props.weekHeaders.map(({ content, classNames }) => { return { - textContent: props.getWeekHeaderString(textContent), + textContent: this.state.getWeekHeaderString(content), className: classNames.join(" ") }; }); @@ -92,8 +95,6 @@ function Calendar(options, context) { this.state.days = days; this.state.weekHeaders = weekHeaders; } - - this.props = Object.assign(this.props, props); }, /** @@ -150,9 +151,9 @@ function Calendar(options, context) { case "click": { if (event.target.parentNode == this.context.daysView) { let targetId = event.target.dataset.id; - let targetObj = this.props.days[targetId]; + let targetObj = this.state.days[targetId]; if (targetObj.enabled) { - this.props.setSelection(targetObj.dateObj); + this.state.setSelection(targetObj.dateObj); } } break; -- cgit v1.2.3