Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/toolkit/content/widgets/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 16 kB image not shown  

Quellcode-Bibliothek calendar.js   Sprache: JAVA

 
/* 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
 *          {Function} setCalendarMonth: Update the month shown by the dateView
 *                     to a specific month of a specific year
 *        }
 * @param {Object} context
 *        {
 *          {DOMElement} weekHeader
 *          {DOMElement} daysView
 *        }
 */

function Calendar(options, context) {
  this.context = context;
  this.context.DAYS_IN_A_WEEK = 7;
  this.state = {
    days: [],
    weekHeaders: [],
    setSelection: options.setSelection,
    setCalendarMonth: options.setCalendarMonth,
    getDayString: options.getDayString,
    getWeekHeaderString: options.getWeekHeaderString,
    focusedDate: null,
  };
  this.elements = {
    weekHeaders: this._generateNodes(
      this.context.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 and place keyboard focus
      this.state.days = days;
      this.state.weekHeaders = weekHeaders;
      this.focusDay();
    }
  },

  /**
   * 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 }) {
    let selected = {};
    let today = {};
    let sameDay = {};
    let firstDay = {};

    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;
      }

      if (el.tagName === "td") {
        el.setAttribute("role""gridcell");

        // Flush states from the previous view
        el.removeAttribute("tabindex");
        el.removeAttribute("aria-disabled");
        el.removeAttribute("aria-selected");
        el.removeAttribute("aria-current");

        // Set new states and properties
        if (
          this.state.focusedDate &&
          this._isSameDayOfMonth(items[i].dateObj, this.state.focusedDate) &&
          !el.classList.contains("outside")
        ) {
          // When any other date was focused previously, send the focus
          // to the same day of month, but only within the current month
          sameDay.el = el;
          sameDay.dateObj = items[i].dateObj;
        }
        if (el.classList.contains("today")) {
          // Current date/today is communicated to assistive technology
          el.setAttribute("aria-current""date");
          if (!el.classList.contains("outside")) {
            today.el = el;
            today.dateObj = items[i].dateObj;
          }
        }
        if (el.classList.contains("selection")) {
          // Selection is communicated to assistive technology
          // and may be included in the focus order when from the current month
          el.setAttribute("aria-selected""true");

          if (!el.classList.contains("outside")) {
            selected.el = el;
            selected.dateObj = items[i].dateObj;
          }
        } else if (el.classList.contains("out-of-range")) {
          // Dates that are outside of the range are not selected and cannot be
          el.setAttribute("aria-disabled""true");
          el.removeAttribute("aria-selected");
        } else {
          // Other dates are not selected, but could be
          el.setAttribute("aria-selected""false");
        }
        if (el.textContent === "1" && !firstDay.el) {
          // When no previous day, no selection, or no current day/today
          // is present, make the first of the month focusable
          firstDay.dateObj = items[i].dateObj;
          firstDay.dateObj.setUTCDate("1");

          if (this._isSameDay(items[i].dateObj, firstDay.dateObj)) {
            firstDay.el = el;
            firstDay.dateObj = items[i].dateObj;
          }
        }
      }
    }

    // The previously focused date (if the picker is updated and the grid still
    // contains the date) is always focusable. The selected date on init is also
    // always focusable. If neither exist, we make the current day or the first
    // day of the month focusable.
    if (sameDay.el) {
      sameDay.el.setAttribute("tabindex""0");
      this.state.focusedDate = new Date(sameDay.dateObj);
    } else if (selected.el) {
      selected.el.setAttribute("tabindex""0");
      this.state.focusedDate = new Date(selected.dateObj);
    } else if (today.el) {
      today.el.setAttribute("tabindex""0");
      this.state.focusedDate = new Date(today.dateObj);
    } else if (firstDay.el) {
      firstDay.el.setAttribute("tabindex""0");
      this.state.focusedDate = new Date(firstDay.dateObj);
    }
  },

  /**
   * Generate DOM nodes with HTML table markup
   *
   * @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 = [];

    // Create table row to present a week:
    let rowEl = document.createElement("tr");
    for (let i = 0; i < size; i++) {
      // Create table cell for a table header (weekday) or body (date)
      let el;
      if (context.classList.contains("week-header")) {
        el = document.createElement("th");
        el.setAttribute("scope""col");
        // Explicitly assigning the role as a workaround for the bug 1711273:
        el.setAttribute("role""columnheader");
      } else {
        el = document.createElement("td");
      }

      el.dataset.id = i;
      refs.push(el);
      rowEl.appendChild(el);

      // Ensure each table row (week) has only
      // seven table cells (days) for a Gregorian calendar
      if ((i + 1) % this.context.DAYS_IN_A_WEEK === 0) {
        frag.appendChild(rowEl);
        rowEl = document.createElement("tr");
      }
    }
    context.appendChild(frag);

    return refs;
  },

  /**
   * Handle events
   * @param  {DOMEvent} event
   */

  handleEvent(event) {
    switch (event.type) {
      case "click": {
        if (this.context.daysView.contains(event.target)) {
          let targetId = event.target.dataset.id;
          let targetObj = this.state.days[targetId];
          if (targetObj.enabled) {
            this.state.setSelection(targetObj.dateObj);
          }
        }
        break;
      }

      case "keydown": {
        // Providing keyboard navigation support in accordance with
        // the ARIA Grid and Dialog design patterns
        if (this.context.daysView.contains(event.target)) {
          // If RTL, the offset direction for Right/Left needs to be reversed
          const direction = Services.locale.isAppLocaleRTL ? -1 : 1;

          switch (event.key) {
            case "Enter":
            case " ": {
              let targetId = event.target.dataset.id;
              let targetObj = this.state.days[targetId];
              if (targetObj.enabled) {
                this.state.setSelection(targetObj.dateObj);
              }
              break;
            }

            case "ArrowRight": {
              // Moves focus to the next day. If the next day is
              // out-of-range, update the view to show the next month
              this._handleKeydownEvent(1 * direction);
              break;
            }
            case "ArrowLeft": {
              // Moves focus to the previous day. If the next day is
              // out-of-range, update the view to show the previous month
              this._handleKeydownEvent(-1 * direction);
              break;
            }
            case "ArrowUp": {
              // Moves focus to the same day of the previous week. If the next
              // day is out-of-range, update the view to show the previous month
              this._handleKeydownEvent(-1 * this.context.DAYS_IN_A_WEEK);
              break;
            }
            case "ArrowDown": {
              // Moves focus to the same day of the next week. If the next
              // day is out-of-range, update the view to show the previous month
              this._handleKeydownEvent(1 * this.context.DAYS_IN_A_WEEK);
              break;
            }
            case "Home": {
              // Moves focus to the first day (ie. Sunday) of the current week
              if (event.ctrlKey) {
                // Moves focus to the first day of the current month
                this.state.focusedDate.setUTCDate(1);
                this._updateKeyboardFocus();
              } else {
                this._handleKeydownEvent(
                  this.state.focusedDate.getUTCDay() * -1
                );
              }
              break;
            }
            case "End": {
              // Moves focus to the last day (ie. Saturday) of the current week
              if (event.ctrlKey) {
                // Moves focus to the last day of the current month
                let lastDateOfMonth = new Date(
                  this.state.focusedDate.getUTCFullYear(),
                  this.state.focusedDate.getUTCMonth() + 1,
                  0
                );
                this.state.focusedDate = lastDateOfMonth;
                this._updateKeyboardFocus();
              } else {
                this._handleKeydownEvent(
                  this.context.DAYS_IN_A_WEEK -
                    1 -
                    this.state.focusedDate.getUTCDay()
                );
              }
              break;
            }
            case "PageUp": {
              // Changes the view to the previous month/year
              // and sets focus on the same day.
              // If that day does not exist, then moves focus
              // to the same day of the same week.
              if (event.shiftKey) {
                // Previous year
                let prevYear = this.state.focusedDate.getUTCFullYear() - 1;
                this.state.focusedDate.setUTCFullYear(prevYear);
              } else {
                // Previous month
                let prevMonth = this.state.focusedDate.getUTCMonth() - 1;
                this.state.focusedDate.setUTCMonth(prevMonth);
              }
              this.state.setCalendarMonth(
                this.state.focusedDate.getUTCFullYear(),
                this.state.focusedDate.getUTCMonth()
              );
              this._updateKeyboardFocus();
              break;
            }
            case "PageDown": {
              // Changes the view to the next month/year
              // and sets focus on the same day.
              // If that day does not exist, then moves focus
              // to the same day of the same week.
              if (event.shiftKey) {
                // Next year
                let nextYear = this.state.focusedDate.getUTCFullYear() + 1;
                this.state.focusedDate.setUTCFullYear(nextYear);
              } else {
                // Next month
                let nextMonth = this.state.focusedDate.getUTCMonth() + 1;
                this.state.focusedDate.setUTCMonth(nextMonth);
              }
              this.state.setCalendarMonth(
                this.state.focusedDate.getUTCFullYear(),
                this.state.focusedDate.getUTCMonth()
              );
              this._updateKeyboardFocus();
              break;
            }
          }
        }
        break;
      }
    }
  },

  /**
   * Attach event listener to daysView
   */

  _attachEventListeners() {
    this.context.daysView.addEventListener("click"this);
    this.context.daysView.addEventListener("keydown"this);
  },

  /**
   * Find Data-id of the next element to focus on the daysView grid
   * @param {Object} nextDate: Data object of the next element to focus
   */

  _calculateNextId(nextDate) {
    for (let i = 0; i < this.state.days.length; i++) {
      if (this._isSameDay(this.state.days[i].dateObj, nextDate)) {
        return i;
      }
    }
    return null;
  },

  /**
   * Comparing two date objects to ensure they produce the same date
   * @param  {Date} dateObj1: Date object from the updated state
   * @param  {Date} dateObj2: Date object from the previous state
   * @return {Boolean} If two date objects are the same day
   */

  _isSameDay(dateObj1, dateObj2) {
    return (
      dateObj1.getUTCFullYear() == dateObj2.getUTCFullYear() &&
      dateObj1.getUTCMonth() == dateObj2.getUTCMonth() &&
      dateObj1.getUTCDate() == dateObj2.getUTCDate()
    );
  },

  /**
   * Comparing two date objects to ensure they produce the same day of the month,
   * while being on different months
   * @param  {Date} dateObj1: Date object from the updated state
   * @param  {Date} dateObj2: Date object from the previous state
   * @return {Boolean} If two date objects are the same day of the month
   */

  _isSameDayOfMonth(dateObj1, dateObj2) {
    return dateObj1.getUTCDate() == dateObj2.getUTCDate();
  },

  /**
   * Manage focus for the keyboard navigation for the daysView grid
   * @param  {Number} offsetDays: The direction and the number of days to move
   *                            the focus by, where a negative number (i.e. -1)
   *                            moves the focus to the previous day
   */

  _handleKeydownEvent(offsetDays) {
    let newFocusedDay = this.state.focusedDate.getUTCDate() + offsetDays;
    let newFocusedDate = new Date(this.state.focusedDate);
    newFocusedDate.setUTCDate(newFocusedDay);

    // Update the month, if the next focused element is outside
    if (newFocusedDate.getUTCMonth() !== this.state.focusedDate.getUTCMonth()) {
      this.state.setCalendarMonth(
        newFocusedDate.getUTCFullYear(),
        newFocusedDate.getUTCMonth()
      );
    }
    this.state.focusedDate.setUTCDate(newFocusedDate.getUTCDate());
    this._updateKeyboardFocus();
  },

  /**
   * Update the daysView grid and send focus to the next day
   * based on the current state fo the Calendar
   */

  _updateKeyboardFocus() {
    this._render({
      elements: this.elements.daysView,
      items: this.state.days,
      prevState: this.state.days,
    });
    this.focusDay();
  },

  /**
   * Place keyboard focus on the calendar grid, when the datepicker is initiated or updated.
   * A "tabindex" attribute is provided to only one date within the grid
   * by the "render()" method and this focusable element will be focused.
   */

  focusDay() {
    const focusable = this.context.daysView.querySelector('[tabindex="0"]');
    if (focusable) {
      focusable.focus();
    }
  },
};

Messung V0.5
C=87 H=84 G=85

¤ Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.0.17Bemerkung:  (vorverarbeitet)  ¤

*Bot Zugriff






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.