view class doc
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365/// FOURJS_START_COPYRIGHT(D,2015)
/// Property of Four Js*
/// (c) Copyright Four Js 2015, 2019. All Rights Reserved.
/// * Trademark of Four Js Development Tools Europe Ltd
///   in the United States and elsewhere
/// 
/// This file can be modified by licensees according to the
/// product manual.
/// FOURJS_END_COPYRIGHT

'use strict';

modulum('DateEditWidgetBase', ['FieldWidgetBase', 'WidgetFactory'],
  function(context, cls) {

    /**
     * DateEdit widget Base class.
     * @class DateEditWidgetBase
     * @memberOf classes
     * @extends classes.FieldWidgetBase
     * @publicdoc Widgets
     */
    cls.DateEditWidgetBase = context.oo.Class(cls.FieldWidgetBase, function($super) {
      return /** @lends classes.DateEditWidgetBase.prototype */ {
        __name: 'DateEditWidgetBase',

        /**
         * @inheritDoc
         */
        __dataContentPlaceholderSelector: '.gbc_dataContentPlaceholder',

        /**
         * Format used to display dates of the calendar
         * @type {?string}
         */
        _displayFormat: null,

        /**
         * Get list of sorted days depending of first day of the week which is defined
         * @type {Array}
         */
        _sortedDays: null,

        /**
         * Callback function used to disable days of calendar (framework api)
         * @type {function}
         */
        _disableDayFn: null,

        /**
         * Chinese format for date
         * @type {boolean}
         */
        _useMingGuoYears: false,

        /**
         * Current date momentjs object of the widget
         * @type {Object}
         */
        _dateObj: null,

        /**
         * Last valid date
         * @type {?string}
         */
        _validValue: null,

        /**
         * Indicates if current date of the calendar has been validated by user
         * @type {boolean}
         */
        _mustValid: false,
        /**
         * Max length of the input field
         * @type {number}
         */
        _maxLength: -1,
        /**
         * To detect if we selected a date using keyboard or mouse
         * @type {boolean}
         */
        _keyPressed: false,
        /**
         * Save last clicked date value. Needed to detect double click
         * @type {?string}
         */
        _lastClickValue: null,
        /**
         * Widget icon used to display/hide calendar
         * @type {HTMLElement}
         */
        _pikerIcon: null,

        /**
         * @inheritDoc
         */
        _initLayout: function() {
          if (!this._ignoreLayout) {
            this._layoutInformation = new cls.LayoutInformation(this);
            this._layoutEngine = new cls.LeafLayoutEngine(this);
            this._layoutInformation.setSingleLineContentOnly(true);
            this._layoutInformation.setReservedDecorationSpace(2);
          }
        },

        /**
         * @inheritDoc
         */
        _initElement: function() {
          $super._initElement.call(this);
          if (this._displayFormat === null) {
            this._displayFormat = 'MM/DD/YYYY'; //default format
          }

          this._inputElement = this._element.getElementsByTagName('input')[0];
          this._pikerIcon = this._element.getElementsByTagName('i')[0];

          this._inputElement.on('input.DateEditWidgetBase', this._onInput.bind(this));
        },

        /**
         * @inheritDoc
         */
        destroy: function() {
          this._pikerIcon = null;
          if (this._inputElement) {
            this._inputElement.off('input.DateEditWidgetBase');
            this._inputElement.remove();
            this._inputElement = null;
          }

          $super.destroy.call(this);
        },

        /**
         * @inheritDoc
         */
        setTextAlign: function(align) {
          this.setStyle('input', {
            'text-align': align
          });
        },

        /**
         * @inheritDoc
         */
        getTextAlign: function() {
          return this.getStyle('input', 'text-align');
        },

        /**
         * Reset input field with last valid date
         */
        setLastValidValue: function() {
          if (this._inputElement) {
            this._inputElement.value = this._validValue;
          }
        },

        /**
         * @inheritDoc
         */
        setReadOnly: function(readonly) {
          $super.setReadOnly.call(this, readonly);
          this._setInputReadOnly(readonly);
        },

        /**
         * Set input readonly attribute if it doesn't have focus or is noentry.
         * @param {boolean} readonly - true to set the edit part as read-only, false otherwise
         */
        _setInputReadOnly: function(readonly) {
          if (readonly) {
            this._inputElement.setAttribute('readonly', 'readonly');
            if (window.browserInfo.isIE || window.browserInfo.isEdge) {
              this._inputElement.removeAttribute('contentEditable');
            }
          } else {
            this._inputElement.removeAttribute('readonly');
            if (window.browserInfo.isIE || window.browserInfo.isEdge) {
              // need to add this to be sure that user can enter text in the field
              // even if setCursorPosition is called before
              this._inputElement.setAttribute('contentEditable', 'true');
            }
          }
        },

        /**
         * Get the current dateedit value
         * @returns {string} the displayed value
         */
        getValue: function() {
          return this._inputElement.value;
        },

        /**
         * @inheritDoc
         */
        setValue: function(dateString, fromVM) {
          $super.setValue.call(this, dateString, fromVM);
          this.setDate(dateString);
        },

        /**
         * Return the current Date object
         * @returns {Object} returns current momentjs date object
         * @publicdoc
         */
        getDate: function() {
          return this._dateObj ? this._dateObj.format(this._displayFormat) : null;
        },

        /**
         * Generate momentjs date object from a string and set it for both the calendar component and the input field
         * @param {string} date - date value in string format
         * @publicdoc
         */
        setDate: function(date) {
          // created date object based on received value using known format (for datepicker)
          if (this._useMingGuoYears) { // Convert Ming Guo year to 4 digit years for datepicker
            var str = cls.DateTimeHelper.mingGuoToGregorianYears(date);
            this._dateObj = context.moment(str, this._displayFormat);
          } else {
            this._dateObj = context.moment(date, this._displayFormat);
          }

          // set non formatted value to input (already formatted by VM depending)
          if (this.getValue() !== date) {
            this._inputElement.value = date;
          }
        },

        /**
         * Set a specified format of date. Default is MM/DD/YYYY
         * @param {string} format - date format used to display and send date to the VM.
         * @publicdoc
         */
        setFormat: function(format) {
          var years = format && format.match(/Y/g);
          if (years && years.length === 3) { // Ming Guo format
            this._useMingGuoYears = true;
            format = format.replace('YYY', 'YYYY');
          }
          if (this._displayFormat !== format) {
            this._displayFormat = format;
          }
        },

        /**
         * Return date format
         * @returns {string} the date format
         * @publicdoc
         */
        getFormat: function() {
          return this._displayFormat;
        },

        /**
         * Get cursors
         * @return {{start: number, end: number}} object with cursors
         * @publicdoc
         */
        getCursors: function() {
          var cursors = {
            start: 0,
            end: 0
          };
          if (this._inputElement && this._inputElement.value) {
            try {
              cursors.start = this._inputElement.selectionStart;
              cursors.end = this._inputElement.selectionEnd;
            } catch (ignore) {
              // Some input types don't allow cursor manipulation
            }
          }
          return cursors;
        },

        /** Place the cursor at the given position,
         * @param {number} cursor - first cursor position
         * @param {number=} cursor2 - second cursor position
         * @publicdoc
         */
        setCursors: function(cursor, cursor2) {
          if (!cursor2) {
            cursor2 = cursor;
          }
          if (cursor2 && cursor2 < 0) {
            cursor2 = this.getValue() && this.getValue().length || 0;
          }
          this._inputElement.setCursorPosition(cursor, cursor2);
        },

        /**
         * @inheritDoc
         */
        setTitle: function(title) {
          this._inputElement.setAttribute('title', title);
        },

        /**
         * @inheritDoc
         */
        getTitle: function() {
          return this._inputElement.getAttribute('title');
        },

        /**
         * @inheritDoc
         */
        setFocus: function(fromMouse) {
          $super.setFocus.call(this, fromMouse);
          this._inputElement.domFocus();
        },

        /**
         * @inheritDoc
         */
        setEnabled: function(enabled) {
          $super.setEnabled.call(this, enabled);
          this._setInputReadOnly(!enabled);
        },

        /**
         * Define the maximum number of characters allowed
         * @param {number} maxlength - maximum number of characters allowed in the field
         * @publicdoc
         */
        setMaxLength: function(maxlength) {
          if (maxlength) {
            this._maxLength = maxlength;
            this._setElementAttribute('maxlength', maxlength, "_inputElement");
          }
        },

        /**
         * Get the maximum number of characters allowed
         * @returns {number} the maximum number of characters allowed in the field
         * @publicdoc
         */
        getMaxLength: function() {
          return this._maxLength;
        },

        /**
         * Defines a different image for the icon of the DateEdit
         * @param {string} icon - src of the image
         */
        setButtonIcon: function(icon) {
          if (!!icon) {
            var img = cls.WidgetFactory.createWidget('Image', this.getBuildParameters());
            var imgElem = img.getElement();
            img.setSrc(icon);
            img.setTitle("Open picker");
            this._pikerIcon.classList.remove('zmdi', 'zmdi-calendar-blank', 'zmdi-calendar-clock');
            this.domAttributesMutator(function() {
              this._pikerIcon.innerHTML = imgElem.innerHTML;
              img.destroy();
            }.bind(this));
          }
        }
      };
    });
  });