"use strict";
/**
 * EGroupware eTemplate2 - JS Date object
 *
 * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
 * @package etemplate
 * @subpackage api
 * @link http://www.egroupware.org
 * @author Nathan Gray
 * @copyright Nathan Gray 2011
 */
var __extends = (this && this.__extends) || (function () {
    var extendStatics = function (d, b) {
        extendStatics = Object.setPrototypeOf ||
            ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
            function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
        return extendStatics(d, b);
    };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.et2_date_range = exports.et2_date_ro = exports.et2_date_duration_ro = exports.et2_date_duration = exports.et2_date = void 0;
/*egw:uses
    /vendor/bower-asset/jquery/dist/jquery.js;
    /vendor/bower-asset/jquery-ui/jquery-ui.js;
    lib/date;
    et2_core_inputWidget;
    et2_core_valueWidget;
*/
require("./et2_core_common");
var et2_core_inheritance_1 = require("./et2_core_inheritance");
var et2_core_widget_1 = require("./et2_core_widget");
var et2_core_valueWidget_1 = require("./et2_core_valueWidget");
var et2_core_inputWidget_1 = require("./et2_core_inputWidget");
var et2_core_DOMWidget_1 = require("./et2_core_DOMWidget");
// all calls to jQueryUI.datetimepicker as jQuery.datepicker give errors which are currently suppressed with @ts-ignore
// adding npm package @types/jquery.ui.datetimepicker did NOT help :(
/**
 * Class which implements the "date" XET-Tag
 *
 * Dates are passed to the server in ISO8601 format ("Y-m-d\TH:i:sP"), and data_format is
 * handled server-side.
 *
 * Widgets uses jQuery date- and time-picker for desktop browsers and
 * HTML5 input fields for mobile devices to get their native UI for date/time entry.
 */
var et2_date = /** @class */ (function (_super) {
    __extends(et2_date, _super);
    /**
     * Constructor
     */
    function et2_date(_parent, _attrs, _child) {
        var _this = 
        // Call the inherited constructor
        _super.call(this, _parent, _attrs, et2_core_inheritance_1.ClassWithAttributes.extendAttributes(et2_date._attributes, _child || {})) || this;
        _this.input_date = null;
        _this.is_mobile = false;
        _this.date = new Date();
        _this.date.setUTCHours(0);
        _this.date.setMinutes(0);
        _this.date.setSeconds(0);
        _this.createInputWidget();
        return _this;
    }
    et2_date.prototype.createInputWidget = function () {
        this.span = jQuery(document.createElement(this.options.inline ? 'div' : "span")).addClass("et2_date");
        this.input_date = jQuery(document.createElement(this.options.inline ? "div" : "input"));
        if (this.options.blur)
            this.input_date.attr('placeholder', this.egw().lang(this.options.blur));
        this.input_date.addClass("et2_date").attr("type", "text")
            .attr("size", 7) // strlen("10:00pm")=7
            .appendTo(this.span);
        this.setDOMNode(this.span[0]);
        // inline calendar is not existing in html5, so allways use datepicker instead
        this.is_mobile = egwIsMobile() && !this.options.inline;
        if (this.is_mobile) {
            this.dateFormat = 'yy-mm-dd';
            this.timeFormat = 'HH:mm';
            switch (this.getType()) {
                case 'date':
                    this.input_date.attr('type', 'date');
                    break;
                case 'date-time':
                    this.input_date.attr('type', 'datetime-local');
                    break;
                case 'date-timeonly':
                    this.input_date.addClass("et2_time");
                    this.input_date.attr('type', 'time');
                    break;
            }
        }
        else {
            this.dateFormat = this.egw().dateTimeFormat(this.egw().preference("dateformat"));
            this.timeFormat = this.egw().preference("timeformat") == 12 ? "h:mmtt" : "HH:mm";
            // jQuery-UI date picker
            if (this.getType() != 'date-timeonly') {
                this.egw().calendar(this.input_date, this.getType() == "date-time");
            }
            else {
                this.input_date.addClass("et2_time");
                this.egw().time(this.input_date);
            }
            // Avoid collision of datepicker dialog with input field
            var widget = this;
            this.input_date.datepicker('option', 'beforeShow', function (input, inst) {
                var cal = inst.dpDiv;
                setTimeout(function () {
                    var $input = jQuery(input);
                    var inputOffset = $input.offset();
                    // position the datepicker in freespace zone
                    // avoid datepicker calendar collision with input field
                    if (cal.height() + inputOffset.top > window.innerHeight) {
                        cal.position({
                            my: "left center",
                            at: 'right bottom',
                            collision: 'flip fit',
                            of: input
                        });
                    }
                    // Add tooltip to Today/Now button
                    jQuery('[data-handler="today"]', cal).attr('title', widget.getType() == 'date' ? egw.lang('Today') : egw.lang('Now'));
                }, 0);
            })
                .datepicker('option', 'onClose', function (dateText, inst) {
                // Lose focus, avoids an issue with focus
                // not allowing datepicker to re-open
                inst.input.blur();
            });
        }
        // Update internal value when changed
        var self = this;
        this.input_date.bind('change', function (e) {
            self.set_value(this.value);
            return false;
        });
        // Framewok skips nulls, but null needs to be processed here
        if (this.options.value == null) {
            this.set_value(null);
        }
    };
    /**
     * Calendar popup sets the ID of the input, we can't change that like other inputWidgets can
     *
     * @param _value
     */
    et2_date.prototype.set_id = function (_value) {
        this.id = _value;
        this.dom_id = _value && this.getInstanceManager() ? this.getInstanceManager().uniqueId + '_' + this.id : _value;
        var node = this.getDOMNode(this);
        if (node) {
            if (_value != "") {
                node.setAttribute("id", this.dom_id);
            }
            else {
                node.removeAttribute("id");
            }
        }
    };
    et2_date.prototype.getInputNode = function () {
        return this.options.inline ? _super.prototype.getInputNode.call(this) : this.input_date[0];
    };
    et2_date.prototype.set_type = function (_type) {
        if (_type != this.getType()) {
            _super.prototype.setType.call(this, _type);
            this.createInputWidget();
        }
    };
    /**
     * Dynamic disable or enable datepicker
     *
     * @param {boolean} _ro
     */
    et2_date.prototype.set_readonly = function (_ro) {
        if (this.input_date && !this.input_date.attr('disabled') != !_ro) {
            this.input_date.prop('disabled', !!_ro)
                .datepicker('option', 'disabled', !!_ro);
        }
    };
    /**
     * Set (full) year of current date
     *
     * @param {number} _value 4-digit year
     */
    et2_date.prototype.set_year = function (_value) {
        this.date.setUTCFullYear(_value);
        this.set_value(this.date);
    };
    /**
     * Set month (1..12) of current date
     *
     * @param {number} _value 1..12
     */
    et2_date.prototype.set_month = function (_value) {
        this.date.setUTCMonth(_value - 1);
        this.set_value(this.date);
    };
    /**
     * Set day of current date
     *
     * @param {number} _value 1..31
     */
    et2_date.prototype.set_date = function (_value) {
        this.date.setUTCDate(_value);
        this.set_value(this.date);
    };
    /**
     * Set hour (0..23) of current date
     *
     * @param {number} _value 0..23
     */
    et2_date.prototype.set_hours = function (_value) {
        this.date.setUTCHours(_value);
        this.set_value(this.date);
    };
    /**
     * Set minute (0..59) of current date
     *
     * @param {number} _value 0..59
     */
    et2_date.prototype.set_minutes = function (_value) {
        this.date.setUTCMinutes(_value);
        this.set_value(this.date);
    };
    /**
     * Get (full) year of current date
     *
     * @return {number|null} 4-digit year or null for empty
     */
    et2_date.prototype.get_year = function () {
        return this.input_date.val() == "" ? null : this.date.getUTCFullYear();
    };
    /**
     * Get month (1..12) of current date
     *
     * @return {number|null} 1..12 or null for empty
     */
    et2_date.prototype.get_month = function () {
        return this.input_date.val() == "" ? null : this.date.getUTCMonth() + 1;
    };
    /**
     * Get day of current date
     *
     * @return {number|null} 1..31 or null for empty
     */
    et2_date.prototype.get_date = function () {
        return this.input_date.val() == "" ? null : this.date.getUTCDate();
    };
    /**
     * Get hour (0..23) of current date
     *
     * @return {number|null} 0..23 or null for empty
     */
    et2_date.prototype.get_hours = function () {
        return this.input_date.val() == "" ? null : this.date.getUTCHours();
    };
    /**
     * Get minute (0..59) of current date
     *
     * @return {number|null} 0..59 or null for empty
     */
    et2_date.prototype.get_minutes = function () {
        return this.input_date.val() == "" ? null : this.date.getUTCMinutes();
    };
    /**
     * Get timestamp
     *
     * You can use set_value to set a timestamp.
     *
     * @return {number|null} timestamp (seconds since 1970-01-01)
     */
    et2_date.prototype.get_time = function () {
        return this.input_date.val() == "" ? null : this.date.getTime();
    };
    /**
     * The range of years displayed in the year drop-down: either relative
     * to today's year ("-nn:+nn"), relative to the currently selected year
     * ("c-nn:c+nn"), absolute ("nnnn:nnnn"), or combinations of these formats
     * ("nnnn:-nn"). Note that this option only affects what appears in the
     * drop-down, to restrict which dates may be selected use the min_date
     * and/or max_date options.
     * @param {string} _value
     */
    et2_date.prototype.set_year_range = function (_value) {
        if (this.input_date && this.getType() == 'date' && !this.is_mobile) {
            this.input_date.datepicker('option', 'yearRange', _value);
        }
        this.options.year_range = _value;
    };
    /**
     * Set the minimum allowed date
     *
     * The minimum selectable date. When set to null, there is no minimum.
     *	Multiple types supported:
     *	Date: A date object containing the minimum date.
     *	Number: A number of days from today. For example 2 represents two days
     *		from today and -1 represents yesterday.
     *	String: A string in the format defined by the dateFormat option, or a
     *		relative date. Relative dates must contain value and period pairs;
     *		valid periods are "y" for years, "m" for months, "w" for weeks, and
     *		"d" for days. For example, "+1m +7d" represents one month and seven
     *		days from today.
     * @param {Date|Number|String} _value
     */
    et2_date.prototype.set_min = function (_value) {
        if (this.input_date) {
            if (this.is_mobile) {
                this.input_date.attr('min', this._relativeDate(_value));
            }
            else {
                // Check for full timestamp
                if (typeof _value == 'string' && _value.match(/(\d{4})-(\d{2})-(\d{2})T(\d{2})\:(\d{2})\:(\d{2})(?:\.\d{3})?(?:Z|[+-](\d{2})\:(\d{2}))/)) {
                    _value = new Date(_value);
                    // Add timezone offset back in, or formatDate will lose those hours
                    var formatDate = new Date(_value.valueOf() + this.date.getTimezoneOffset() * 60 * 1000);
                    if (this.getType() == 'date') {
                        _value = jQuery.datepicker.formatDate(this.dateFormat, formatDate);
                    }
                }
                this.input_date.datepicker('option', 'minDate', _value);
            }
        }
        this.options.min = _value;
    };
    /**
     * Convert non html5 min or max attributes described above to timestamps
     *
     * @param {string|Date} _value
     */
    et2_date.prototype._relativeDate = function (_value) {
        if (typeof _value == 'string' && _value.match(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}/))
            return _value;
        // @ts-ignore
        return jQuery.datepicker._determineDate(jQuery.datepicker, _value, this.date).toJSON();
    };
    /**
     * Set the maximum allowed date
     *
     * The maximum selectable date. When set to null, there is no maximum.
     *	Multiple types supported:
     *	Date: A date object containing the maximum date.
     *	Number: A number of days from today. For example 2 represents two days
     *		from today and -1 represents yesterday.
     *	String: A string in the format defined by the dateFormat option, or a
     *		relative date. Relative dates must contain value and period pairs;
     *		valid periods are "y" for years, "m" for months, "w" for weeks, and
     *		"d" for days. For example, "+1m +7d" represents one month and seven
     *		days from today.
     * @param {Date|Number|String} _value
     */
    et2_date.prototype.set_max = function (_value) {
        if (this.input_date) {
            if (this.is_mobile) {
                this.input_date.attr('max', this._relativeDate(_value));
            }
            else {
                // Check for full timestamp
                if (typeof _value == 'string' && _value.match(/(\d{4})-(\d{2})-(\d{2})T(\d{2})\:(\d{2})\:(\d{2})(?:\.\d{3})?(?:Z|[+-](\d{2})\:(\d{2}))/)) {
                    _value = new Date(_value);
                    // Add timezone offset back in, or formatDate will lose those hours
                    var formatDate = new Date(_value.valueOf() + this.date.getTimezoneOffset() * 60 * 1000);
                    if (this.getType() == 'date') {
                        _value = jQuery.datepicker.formatDate(this.dateFormat, formatDate);
                    }
                }
                this.input_date.datepicker('option', 'maxDate', _value);
            }
        }
        this.options.max = _value;
    };
    /**
     * Setting date
     *
     * @param {string|number|Date} _value supported are the following formats:
     * - Date object with usertime as UTC value
     * - string like Date.toJSON()
     * - string or number with timestamp in usertime like server-side uses it
     * - string starting with + or - to add/substract given number of seconds from current value, "+600" to add 10 minutes
     */
    et2_date.prototype.set_value = function (_value) {
        var old_value = this._oldValue;
        if (_value === null || _value === "" || _value === undefined ||
            // allow 0 as empty-value for date and date-time widgets, as that is used a lot eg. in InfoLog
            _value == 0 && (this.getType() == 'date-time' || this.getType() == 'date')) {
            if (this.input_date) {
                this.input_date.val("");
            }
            if (this._oldValue !== et2_no_init && old_value !== _value) {
                this.change(this.input_date);
            }
            this._oldValue = _value;
            return;
        }
        // timestamp in usertime, convert to 'Y-m-d\\TH:i:s\\Z', as we do on server-side with equivalent of PHP date()
        if (typeof _value == 'number' || typeof _value == 'string' && !isNaN(_value) && _value[0] != '+' && _value[0] != '-') {
            _value = date('Y-m-d\\TH:i:s\\Z', _value);
        }
        // Check for full timestamp
        if (typeof _value == 'string' && _value.match(/^(\d{4})-(\d{2})-(\d{2})T(\d{2})\:(\d{2})\:(\d{2})(?:\.\d{3})?(?:Z|[+-](\d{2})\:(\d{2})|)$/)) {
            _value = new Date(_value);
        }
        // Handle just time as a string in the form H:i
        if (typeof _value == 'string' && isNaN(_value)) {
            try {
                // silently fix skiped minutes or times with just one digit, as parser is quite pedantic ;-)
                var fix_reg = new RegExp((this.getType() == "date-timeonly" ? '^' : ' ') + '([0-9]+)(:[0-9]*)?( ?(a|p)m?)?$', 'i');
                var matches = _value.match(fix_reg);
                if (matches && (matches[1].length < 2 || matches[2] === undefined || matches[2].length < 3 ||
                    matches[3] && matches[3] != 'am' && matches[3] != 'pm')) {
                    if (matches[1].length < 2 && !matches[3])
                        matches[1] = '0' + matches[1];
                    if (matches[2] === undefined)
                        matches[2] = ':00';
                    while (matches[2].length < 3)
                        matches[2] = ':0' + matches[2].substr(1);
                    _value = _value.replace(fix_reg, (this.getType() == "date-timeonly" ? '' : ' ') + matches[1] + matches[2] + matches[3]);
                    if (matches[4] !== undefined)
                        matches[3] = matches[4].toLowerCase() == 'a' ? 'am' : 'pm';
                }
                switch (this.getType()) {
                    case "date-timeonly":
                        // @ts-ignore
                        var parsed = jQuery.datepicker.parseTime(this.timeFormat, _value);
                        if (!parsed) // parseTime returns false
                         {
                            this.set_validation_error(this.egw().lang("'%1' has an invalid format !!!", _value));
                            return;
                        }
                        this.set_validation_error(false);
                        // this.date is on current date, changing it in get_value() to 1970-01-01, gives a time-difference, if we are currently on DST
                        this.date.setDate(1);
                        this.date.setMonth(0);
                        this.date.setFullYear(1970);
                        // Avoid javascript timezone offset, hour is in 'user time'
                        this.date.setUTCHours(parsed.hour);
                        this.date.setMinutes(parsed.minute);
                        if (this.input_date.val() != _value) {
                            this.input_date.val(_value);
                            // @ts-ignore
                            this.input_date.timepicker('setTime', _value);
                            if (this._oldValue !== et2_no_init) {
                                this.change(this.input_date);
                            }
                        }
                        this._oldValue = this.date.toJSON();
                        return;
                    default:
                        // Parse customfields's date with storage data_format to date object
                        // Or generally any date widgets with fixed date/time format
                        if (this.id.match(/^#/g) && this.options.value == _value || (this.options.data_format && this.options.value == _value)) {
                            switch (this.getType()) {
                                case 'date':
                                    var parsed = jQuery.datepicker.parseDate(this.egw().dateTimeFormat(this.options.data_format), _value);
                                    break;
                                case 'date-time':
                                    var DTformat = this.options.data_format.split(' ');
                                    // @ts-ignore
                                    var parsed = jQuery.datepicker.parseDateTime(this.egw().dateTimeFormat(DTformat[0]), this.egw().dateTimeFormat(DTformat[1]), _value);
                            }
                        }
                        else // Parse other date widgets date with timepicker date/time format to date onject
                         {
                            // @ts-ignore
                            var parsed = jQuery.datepicker.parseDateTime(this.dateFormat, this.timeFormat, _value.replace('T', ' '));
                            if (!parsed) {
                                this.set_validation_error(this.egw().lang("%1' han an invalid format !!!", _value));
                                return;
                            }
                        }
                        // Update local variable, but remove the timezone offset that
                        // javascript adds when we parse
                        if (parsed) {
                            this.date = new Date(parsed.valueOf() - parsed.getTimezoneOffset() * 60000);
                        }
                        this.set_validation_error(false);
                }
            }
            // catch exception from unparsable date and display it empty instead
            catch (e) {
                return this.set_value(null);
            }
        }
        else if (typeof _value == 'object' && _value.date) {
            this.date = _value.date;
        }
        else if (typeof _value == 'object' && _value.valueOf) {
            this.date = _value;
        }
        else 
        // string starting with + or - --> add/substract number of seconds from current value
        {
            this.date.setTime(this.date.getTime() + 1000 * parseInt(_value));
        }
        // Update input - popups do, but framework doesn't
        _value = '';
        // Add timezone offset back in, or formatDate will lose those hours
        var formatDate = new Date(this.date.valueOf() + this.date.getTimezoneOffset() * 60 * 1000);
        if (this.getType() != 'date-timeonly') {
            _value = jQuery.datepicker.formatDate(this.dateFormat, formatDate);
        }
        if (this.getType() != 'date') {
            if (this.getType() != 'date-timeonly')
                _value += this.is_mobile ? 'T' : ' ';
            // @ts-ignore
            _value += jQuery.datepicker.formatTime(this.timeFormat, {
                hour: formatDate.getHours(),
                minute: formatDate.getMinutes(),
                seconds: 0,
                timezone: 0
            });
        }
        if (this.options.inline) {
            this.input_date.datepicker("setDate", formatDate);
        }
        else {
            this.input_date.val(_value);
        }
        if (this._oldValue !== et2_no_init && old_value != this.getValue()) {
            this.change(this.input_date);
        }
        this._oldValue = _value;
    };
    et2_date.prototype.getValue = function () {
        if (this.input_date.val() == "") {
            // User blanked the box
            return null;
        }
        // date-timeonly returns just the seconds, without any date!
        if (this.getType() == 'date-timeonly') {
            this.date.setUTCDate(1);
            this.date.setUTCMonth(0);
            this.date.setUTCFullYear(1970);
        }
        else if (this.getType() == 'date') {
            this.date.setUTCHours(0);
            this.date.setUTCMinutes(0);
        }
        // Convert to timestamp - no seconds
        this.date.setSeconds(0, 0);
        return (this.date && typeof this.date.toJSON != 'undefined' && this.date.toJSON()) ? this.date.toJSON().replace(/\.\d{3}Z$/, 'Z') : this.date;
    };
    et2_date._attributes = {
        "value": {
            "type": "any"
        },
        "type": {
            "ignore": false
        },
        "blur": {
            "name": "Placeholder",
            "type": "string",
            "default": "",
            "description": "This text get displayed if an input-field is empty and does not have the input-focus (blur). It can be used to show a default value or a kind of help-text."
        },
        "data_format": {
            "ignore": true,
            "description": "Date/Time format. Can be set as an options to date widget",
            "default": ''
        },
        year_range: {
            name: "Year range",
            type: "string",
            default: "c-10:c+10",
            description: "The range of years displayed in the year drop-down: either relative to today's year (\"-nn:+nn\"), relative to the currently selected year (\"c-nn:c+nn\"), absolute (\"nnnn:nnnn\"), or combinations of these formats (\"nnnn:-nn\"). Note that this option only affects what appears in the drop-down, to restrict which dates may be selected use the min and/or max options."
        },
        min: {
            "name": "Minimum",
            "type": "any",
            "default": et2_no_init,
            "description": 'Minimum allowed date.  Multiple types supported:\
Date: A date object containing the minimum date.\
Number: A number of days from today. For example 2 represents two days from today and -1 represents yesterday.\
String: A string in the user\'s date format, or a relative date. Relative dates must contain value and period pairs; valid periods are "y" for years, "m" for months, "w" for weeks, and "d" for days. For example, "+1m +7d" represents one month and seven days from today.'
        },
        max: {
            "name": "Maximum",
            "type": "any",
            "default": et2_no_init,
            "description": 'Maximum allowed date.   Multiple types supported:\
Date: A date object containing the maximum date.\
Number: A number of days from today. For example 2 represents two days from today and -1 represents yesterday.\
String: A string in the user\'s date format, or a relative date. Relative dates must contain value and period pairs; valid periods are "y" for years, "m" for months, "w" for weeks, and "d" for days. For example, "+1m +7d" represents one month and seven days from today.'
        },
        inline: {
            "name": "Inline",
            "type": "boolean",
            "default": false,
            "description": "Instead of an input field with a popup calendar, the calendar is displayed inline, with no input field"
        }
    };
    et2_date.legacyOptions = ["data_format"];
    return et2_date;
}(et2_core_inputWidget_1.et2_inputWidget));
exports.et2_date = et2_date;
et2_core_widget_1.et2_register_widget(et2_date, ["date", "date-time", "date-timeonly"]);
/**
 * Class which implements the "date-duration" XET-Tag
 */
var et2_date_duration = /** @class */ (function (_super) {
    __extends(et2_date_duration, _super);
    /**
     * Constructor
     */
    function et2_date_duration(_parent, _attrs, _child) {
        var _this = 
        // Call the inherited constructor
        _super.call(this, _parent, _attrs, et2_core_inheritance_1.ClassWithAttributes.extendAttributes(et2_date_duration._attributes, _child || {})) || this;
        _this.format = null;
        // Legacy option put percent in with display format
        if (_this.options.display_format.indexOf("%") != -1) {
            _this.options.percent_allowed = true;
            _this.options.display_format = _this.options.display_format.replace("%", "");
        }
        // Clean formats
        _this.options.display_format = _this.options.display_format.replace(/[^dhms]/, '');
        if (!_this.options.display_format) {
            // @ts-ignore
            _this.options.display_format = _this.attributes.display_format["default"];
        }
        // Get translations
        _this.time_formats = {
            d: _this.options.short_labels ? _this.egw().lang("d") : _this.egw().lang("Days"),
            h: _this.options.short_labels ? _this.egw().lang("h") : _this.egw().lang("Hours"),
            m: _this.options.short_labels ? _this.egw().lang("m") : _this.egw().lang("Minutes"),
            s: _this.options.short_labels ? _this.egw().lang("s") : _this.egw().lang("Seconds")
        },
            _this.createInputWidget();
        return _this;
    }
    et2_date_duration.prototype.createInputWidget = function () {
        // Create nodes
        this.node = jQuery(document.createElement("span"))
            .addClass('et2_date_duration');
        var inputs = [];
        for (var i = this.options.select_unit ? 1 : this.options.display_format.length; i > 0; --i) {
            var input = document.createElement("input");
            inputs.push(input);
            if (!this.options.select_unit) {
                var attr = { min: 0 };
                switch (this.options.display_format[this.options.display_format.length - i]) {
                    case 's':
                        attr.max = 60;
                        attr.title = this.egw().lang('Seconds');
                        break;
                    case 'm':
                        attr.max = 60;
                        attr.title = this.egw().lang('Minutes');
                        break;
                    case 'h':
                        attr.max = 24;
                        attr.title = this.egw().lang('Hours');
                        break;
                    case 'd':
                        attr.title = this.egw().lang('Days');
                        break;
                }
                jQuery(input).attr(attr);
            }
        }
        this.duration = jQuery(inputs)
            .addClass('et2_date_duration')
            .attr({
            type: 'number',
            size: 3,
            step: this.options.step,
            lang: this.egw().preference('number_format')[0] === "," ? "en-150" : "en-001"
        });
        this.node.append(this.duration);
        var self = this;
        // seems the 'invalid' event doesn't work in all browsers, eg. FF therefore
        // we use focusout event to check the valifdity of input right after user
        // enters the value.
        this.duration.on('focusout', function () {
            if (!self.duration[0].checkValidity())
                return self.duration.change();
        });
    };
    /**
     * Clientside validation
     *
     * @param {array} _messages
     */
    et2_date_duration.prototype.isValid = function (_messages) {
        var ok = true;
        // if we have a html5 validation error, show it, as this.input.val() will be empty!
        for (var i = 0; this.duration && i < this.duration.length; ++i) {
            if (this.duration[i] &&
                this.duration[i].validationMessage &&
                !this.duration[i].validity.stepMismatch) {
                _messages.push(this.duration[i].validationMessage);
                ok = false;
            }
        }
        return _super.prototype.isValid.call(this, _messages) && ok;
    };
    et2_date_duration.prototype.attachToDOM = function () {
        if (this.duration) {
            for (var i = 0; i < this.duration.length; ++i) {
                var node = this.duration[i];
                jQuery(node).bind("change.et2_inputWidget", this, function (e) {
                    e.data.change(this);
                });
            }
        }
        return et2_core_DOMWidget_1.et2_DOMWidget.prototype.attachToDOM.apply(this, arguments);
    };
    et2_date_duration.prototype.getDOMNode = function () {
        return this.node[0];
    };
    et2_date_duration.prototype.getInputNode = function () {
        return this.duration[0];
    };
    /**
     * Use id on node, same as DOMWidget
     *
     * @param {string} _value id to set
     */
    et2_date_duration.prototype.set_id = function (_value) {
        this.id = _value;
        var node = this.getDOMNode();
        if (node) {
            if (_value != "") {
                node.setAttribute("id", this.getInstanceManager().uniqueId + '_' + this.id);
            }
            else {
                node.removeAttribute("id");
            }
        }
    };
    et2_date_duration.prototype._unit2seconds = function (_unit) {
        switch (_unit) {
            case 's':
                return 1;
            case 'm':
                return 60;
            case 'h':
                return 3600;
            case 'd':
                return 3600 * this.options.hours_per_day;
        }
    };
    et2_date_duration.prototype._unit_from_value = function (_value, _unit, _highest) {
        _value *= this._unit2seconds(this.data_format);
        // get value for given _unit
        switch (_unit) {
            case 's':
                return _highest ? _value : _value % 60;
            case 'm':
                _value = Math.floor(_value / 60);
                return _highest ? _value : _value % 60;
            case 'h':
                _value = Math.floor(_value / 3600);
                return _highest ? _value : _value % this.options.hours_per_day;
            case 'd':
                return Math.floor(_value / 3600 * this.options.hours_per_day);
        }
    };
    et2_date_duration.prototype.set_value = function (_value) {
        this.options.value = _value;
        if (!this.options.select_unit && this.options.display_format.length > 1) {
            for (var i = this.options.display_format.length; --i >= 0;) {
                jQuery(this.duration[i]).val(this._unit_from_value(_value, this.options.display_format[i], !i));
            }
            return;
        }
        var display = this._convert_to_display(parseFloat(_value));
        // Set display
        if (this.duration[0].nodeName == "INPUT") {
            this.duration.val(display.value);
        }
        else {
            this.duration.text(display.value + " ");
        }
        // Set unit as figured for display
        if (display.unit && display.unit != this.options.display_format) {
            if (this.format && this.format.children().length > 1) {
                jQuery("option[value='" + display.unit + "']", this.format).attr('selected', 'selected');
            }
            else {
                this.format.text(display.unit ? this.time_formats[display.unit] : '');
            }
        }
    };
    et2_date_duration.prototype.set_display_format = function (format) {
        if (format.length < 1) {
            this.node.remove('select.et2_date_duration');
            this.format.remove();
            this.format = null;
        }
        this.options.display_format = format;
        if ((this.format == null || this.format.is('select')) &&
            (this.options.display_format.length <= 1 || this.options.readonly || !this.options.select_unit)) {
            if (this.format) {
                this.format.remove();
            }
            this.format = jQuery(document.createElement('span')).appendTo(this.node);
        }
        if (!this.options.select_unit && this.options.display_format.length > 1) {
            // no unit selection or display
            this.format.hide();
        }
        else if (this.options.display_format.length > 1 && !this.options.readonly) {
            if (this.format && !this.format.is('select')) {
                this.format.remove();
                this.format = null;
            }
            if (!this.format) {
                this.format = jQuery(document.createElement("select"))
                    .addClass('et2_date_duration');
                this.node.append(this.format);
            }
            this.format.empty();
            for (var i = 0; i < this.options.display_format.length; i++) {
                this.format.append("<option value='" + this.options.display_format[i] + "'>" + this.time_formats[this.options.display_format[i]] + "</option>");
            }
        }
        else if (this.time_formats[this.options.display_format]) {
            this.format.text(this.time_formats[this.options.display_format]);
        }
        else {
            this.format.text(this.time_formats["m"]);
        }
    };
    /**
     * Converts the value in data format into value in display format.
     *
     * @param _value int/float Data in data format
     *
     * @return Object {value: Value in display format, unit: unit for display}
     */
    et2_date_duration.prototype._convert_to_display = function (_value) {
        if (!this.options.select_unit) {
            var vals = [];
            for (var i = 0; i < this.options.display_format.length; ++i) {
                var unit = this.options.display_format[i];
                var val = this._unit_from_value(_value, unit, i === 0);
                if (unit === 's' || unit === 'm' || unit === 'h' && this.options.display_format[0] === 'd') {
                    vals.push(sprintf('%02d', val));
                }
                else {
                    vals.push(val);
                }
            }
            return { value: vals.join(':'), unit: '' };
        }
        if (_value) {
            // Put value into minutes for further processing
            switch (this.options.data_format) {
                case 'd':
                    _value *= this.options.hours_per_day;
                // fall-through
                case 'h':
                    _value *= 60;
                    break;
                case 's':
                    _value /= 60.0;
                    break;
            }
        }
        // Figure out best unit for display
        var _unit = this.options.display_format == "d" ? "d" : "h";
        if (this.options.display_format.indexOf('m') > -1 && _value && _value < 60) {
            _unit = 'm';
        }
        else if (this.options.display_format.indexOf('d') > -1 && _value >= 60 * this.options.hours_per_day) {
            _unit = 'd';
        }
        _value = this.options.empty_not_0 && _value === '' || !this.options.empty_not_0 && !_value ? '' :
            (_unit == 'm' ? parseInt(_value) : (Math.round((_value / 60.0 / (_unit == 'd' ? this.options.hours_per_day : 1)) * 100) / 100));
        if (_value === '')
            _unit = '';
        // use decimal separator from user prefs
        var format = this.egw().preference('number_format');
        var sep = format ? format[0] : '.';
        if (typeof _value == 'string' && format && sep && sep != '.') {
            _value = _value.replace('.', sep);
        }
        return { value: _value, unit: _unit };
    };
    /**
     * Change displayed value into storage value and return
     */
    et2_date_duration.prototype.getValue = function () {
        if (!this.options.select_unit && this.options.display_format.length > 1) {
            var value_1 = 0;
            for (var i = this.options.display_format.length; --i >= 0;) {
                value_1 += parseInt(jQuery(this.duration[i]).val()) * this._unit2seconds(this.options.display_format[i]);
            }
            if (this.options.data_format !== 's') {
                value_1 /= this._unit2seconds(this.options.data_format);
            }
            return this.options.data_format === 'm' ? Math.round(value_1) : value_1;
        }
        var value = this.duration.val().replace(',', '.');
        if (value === '') {
            return this.options.empty_not_0 ? '' : 0;
        }
        // Put value into minutes for further processing
        switch (this.format && this.format.val() ? this.format.val() : this.options.display_format) {
            case 'd':
                value *= this.options.hours_per_day;
            // fall-through
            case 'h':
                value *= 60;
                break;
        }
        // Minutes should be an integer.  Floating point math.
        if (this.options.data_format !== 's') {
            value = Math.round(value);
        }
        switch (this.options.data_format) {
            case 'd':
                value /= this.options.hours_per_day;
            // fall-through
            case 'h':
                value /= 60.0;
                break;
            case 's':
                value = Math.round(value * 60.0);
                break;
        }
        return value;
    };
    et2_date_duration._attributes = {
        "data_format": {
            "name": "Data format",
            "default": "m",
            "type": "string",
            "description": "Units to read/store the data.  'd' = days (float), 'h' = hours (float), 'm' = minutes (int), 's' = seconds (int)."
        },
        "display_format": {
            "name": "Display format",
            "default": "dhm",
            "type": "string",
            "description": "Permitted units for displaying the data.  'd' = days, 'h' = hours, 'm' = minutes, 's' = seconds.  Use combinations to give a choice.  Default is 'dh' = days or hours with selectbox."
        },
        "select_unit": {
            "name": "Select unit or input per unit",
            "default": true,
            "type": "boolean",
            "description": "Display a unit-selection for multiple units, or an input field per unit."
        },
        "percent_allowed": {
            "name": "Percent allowed",
            "default": false,
            "type": "boolean",
            "description": "Allows to enter a percentage."
        },
        "hours_per_day": {
            "name": "Hours per day",
            "default": 8,
            "type": "integer",
            "description": "Number of hours in a day, for converting between hours and (working) days."
        },
        "empty_not_0": {
            "name": "0 or empty",
            "default": false,
            "type": "boolean",
            "description": "Should the widget differ between 0 and empty, which get then returned as NULL"
        },
        "short_labels": {
            "name": "Short labels",
            "default": false,
            "type": "boolean",
            "description": "use d/h/m instead of day/hour/minute"
        },
        "step": {
            "name": "Step limit",
            "default": 'any',
            "type": "string",
            "description": "Works with the min and max attributes to limit the increments at which a numeric or date-time value can be set."
        }
    };
    et2_date_duration.legacyOptions = ["data_format", "display_format", "hours_per_day", "empty_not_0", "short_labels"];
    return et2_date_duration;
}(et2_date));
exports.et2_date_duration = et2_date_duration;
et2_core_widget_1.et2_register_widget(et2_date_duration, ["date-duration"]);
/**
 * r/o date-duration
 */
var et2_date_duration_ro = /** @class */ (function (_super) {
    __extends(et2_date_duration_ro, _super);
    function et2_date_duration_ro() {
        return _super !== null && _super.apply(this, arguments) || this;
    }
    et2_date_duration_ro.prototype.createInputWidget = function () {
        this.node = jQuery(document.createElement("span"));
        this.duration = jQuery(document.createElement("span")).appendTo(this.node);
        this.format = jQuery(document.createElement("span")).appendTo(this.node);
    };
    /**
     * Code for implementing et2_IDetachedDOM
     * Fast-clonable read-only widget that only deals with DOM nodes, not the widget tree
     */
    /**
     * Build a list of attributes which can be set when working in the
     * "detached" mode in the _attrs array which is provided
     * by the calling code.
     *
     * @param {array} _attrs array to add further attributes to
     */
    et2_date_duration_ro.prototype.getDetachedAttributes = function (_attrs) {
        _attrs.push("value");
    };
    /**
     * Returns an array of DOM nodes. The (relativly) same DOM-Nodes have to be
     * passed to the "setDetachedAttributes" function in the same order.
     *
     * @return {array}
     */
    et2_date_duration_ro.prototype.getDetachedNodes = function () {
        return [this.duration[0], this.format[0]];
    };
    /**
     * Sets the given associative attribute->value array and applies the
     * attributes to the given DOM-Node.
     *
     * @param _nodes is an array of nodes which has to be in the same order as
     *      the nodes returned by "getDetachedNodes"
     * @param _values is an associative array which contains a subset of attributes
     *      returned by the "getDetachedAttributes" function and sets them to the
     *      given values.
     */
    et2_date_duration_ro.prototype.setDetachedAttributes = function (_nodes, _values) {
        for (var i = 0; i < _nodes.length; i++) {
            // Clear the node
            for (var j = _nodes[i].childNodes.length - 1; j >= 0; j--) {
                _nodes[i].removeChild(_nodes[i].childNodes[j]);
            }
        }
        if (typeof _values.value !== 'undefined') {
            _values.value = parseFloat(_values.value);
        }
        if (_values.value) {
            var display = this._convert_to_display(_values.value);
            _nodes[0].appendChild(document.createTextNode(display.value));
            _nodes[1].appendChild(document.createTextNode(display.unit));
        }
    };
    return et2_date_duration_ro;
}(et2_date_duration));
exports.et2_date_duration_ro = et2_date_duration_ro;
et2_core_widget_1.et2_register_widget(et2_date_duration_ro, ["date-duration_ro"]);
/**
 * et2_date_ro is the readonly implementation of some date widget.
 */
var et2_date_ro = /** @class */ (function (_super) {
    __extends(et2_date_ro, _super);
    /**
     * Constructor
     */
    function et2_date_ro(_parent, _attrs, _child) {
        var _this = 
        // Call the inherited constructor
        _super.call(this, _parent, _attrs, et2_core_inheritance_1.ClassWithAttributes.extendAttributes(et2_date_ro._attributes, _child || {})) || this;
        /**
         * Internal container for working easily with dates
         */
        _this.date = new Date();
        _this.value = "";
        _this._labelContainer = jQuery(document.createElement("label"))
            .addClass("et2_label");
        _this.span = jQuery(document.createElement(_this.getType() == "date-since" || _this.getType() == "date-time_today" ? "span" : "time"))
            .addClass("et2_date_ro et2_label")
            .appendTo(_this._labelContainer);
        _this.setDOMNode(_this._labelContainer[0]);
        return _this;
    }
    et2_date_ro.prototype.set_value = function (_value) {
        if (typeof _value == 'undefined')
            _value = 0;
        this.value = _value;
        if (_value == 0 || _value == null) {
            this.span.attr("datetime", "").text("");
            return;
        }
        if (typeof _value == 'string' && _value.match(/(\d{4})-(\d{2})-(\d{2})T(\d{2})\:(\d{2})\:(\d{2})(?:\.\d{3})?(?:Z|[+-](\d{2})\:(\d{2}))/)) {
            this.date = new Date(_value);
            this.date = new Date(this.date.valueOf() + (this.date.getTimezoneOffset() * 60 * 1000));
        }
        else if (typeof _value == 'string' && (isNaN(_value) ||
            this.options.data_format && this.options.data_format.substr(0, 3) === 'Ymd')) {
            try {
                // data_format is not handled server-side for custom-fields in nextmatch
                // as parseDateTime requires a separate between date and time, we fix the value here
                switch (this.options.data_format) {
                    case 'Ymd':
                    case 'YmdHi':
                    case 'YmdHis':
                        _value = _value.substr(0, 4) + '-' + _value.substr(4, 2) + '-' + _value.substr(6, 2) + ' ' +
                            (_value.substr(8, 2) || '00') + ':' + (_value.substr(10, 2) || '00') + ':' + (_value.substr(12, 2) || '00');
                        break;
                }
                // parseDateTime to handle string PHP: DateTime local date/time format
                // @ts-ignore
                var parsed = (typeof jQuery.datepicker.parseDateTime("yy-mm-dd", "hh:mm:ss", _value) != 'undefined') ?
                    // @ts-ignore
                    jQuery.datepicker.parseDateTime("yy-mm-dd", "hh:mm:ss", _value) :
                    // @ts-ignore
                    jQuery.datepicker.parseDateTime(this.egw().preference('dateformat'), this.egw().preference('timeformat') == '24' ? 'H:i' : 'g:i a', _value);
            }
            // display unparsable dates as empty
            catch (e) {
                this.span.attr("datetime", "").text("");
                return;
            }
            var text = new Date(parsed);
            // Update local variable, but remove the timezone offset that javascript adds
            if (parsed) {
                this.date = new Date(text.valueOf() - (text.getTimezoneOffset() * 60 * 1000));
            }
            // JS dates use milliseconds
            this.date.setTime(text.valueOf());
        }
        else {
            // _value is timestamp in usertime, ready to be used with date() function identical to PHP date()
            this.date = _value;
        }
        var display = this.date.toString();
        switch (this.getType()) {
            case "time_or_date":
            case "date-time_today":
                // Today - just the time
                if (date('Y-m-d', this.date) == date('Y-m-d')) {
                    display = date(this.egw().preference('timeformat') == '24' ? 'H:i' : 'g:i a', this.date);
                }
                else if (this.getType() === "time_or_date") {
                    display = date(this.egw().preference('dateformat'), this.date);
                }
                // Before today - date and time
                else {
                    display = date(this.egw().preference('dateformat') + " " +
                        (this.egw().preference('timeformat') == '24' ? 'H:i' : 'g:i a'), this.date);
                }
                break;
            case "date":
                display = date(this.egw().preference('dateformat'), this.date);
                break;
            case "date-timeonly":
                display = date(this.egw().preference('timeformat') == '24' ? 'H:i' : 'g:i a', this.date);
                break;
            case "date-time":
                display = date(this.egw().preference('dateformat') + " " +
                    (this.egw().preference('timeformat') == '24' ? 'H:i' : 'g:i a'), this.date);
                break;
            case "date-since":
                var unit2label = {
                    'Y': 'years',
                    'm': 'month',
                    'd': 'days',
                    'H': 'hours',
                    'i': 'minutes',
                    's': 'seconds'
                };
                var unit2s = {
                    'Y': 31536000,
                    'm': 2628000,
                    'd': 86400,
                    'H': 3600,
                    'i': 60,
                    's': 1
                };
                var d = new Date();
                var diff = Math.round(d.valueOf() / 1000) - Math.round(this.date.valueOf() / 1000);
                display = '';
                for (var unit in unit2s) {
                    var unit_s = unit2s[unit];
                    if (diff >= unit_s || unit == 's') {
                        display = Math.round(diff / unit_s) + ' ' + this.egw().lang(unit2label[unit]);
                        break;
                    }
                }
                break;
        }
        this.span.attr("datetime", date("Y-m-d H:i:s", this.date)).text(display);
    };
    et2_date_ro.prototype.set_label = function (label) {
        // Remove current label
        this._labelContainer.contents()
            .filter(function () { return this.nodeType == 3; }).remove();
        var parts = et2_csvSplit(label, 2, "%s");
        this._labelContainer.prepend(parts[0]);
        this._labelContainer.append(parts[1]);
        this.label = label;
        // add class if label is empty
        this._labelContainer.toggleClass('et2_label_empty', !label || !parts[0]);
    };
    /**
     * Creates a list of attributes which can be set when working in the
     * "detached" mode. The result is stored in the _attrs array which is provided
     * by the calling code.
     *
     * @param {array} _attrs array to add further attributes to
     */
    et2_date_ro.prototype.getDetachedAttributes = function (_attrs) {
        _attrs.push("label", "value", "class");
    };
    /**
     * Returns an array of DOM nodes. The (relatively) same DOM-Nodes have to be
     * passed to the "setDetachedAttributes" function in the same order.
     *
     * @return {array}
     */
    et2_date_ro.prototype.getDetachedNodes = function () {
        return [this._labelContainer[0], this.span[0]];
    };
    /**
     * Sets the given associative attribute->value array and applies the
     * attributes to the given DOM-Node.
     *
     * @param _nodes is an array of nodes which have to be in the same order as
     *      the nodes returned by "getDetachedNodes"
     * @param _values is an associative array which contains a subset of attributes
     *      returned by the "getDetachedAttributes" function and sets them to the
     *      given values.
     */
    et2_date_ro.prototype.setDetachedAttributes = function (_nodes, _values) {
        this._labelContainer = jQuery(_nodes[0]);
        this.span = jQuery(_nodes[1]);
        this.set_value(_values["value"]);
        if (_values["label"]) {
            this.set_label(_values["label"]);
        }
        if (_values["class"]) {
            this.span.addClass(_values["class"]);
        }
    };
    /**
     * Ignore all more advanced attributes.
     */
    et2_date_ro._attributes = {
        "value": {
            "type": "string"
        },
        "type": {
            "ignore": false
        },
        "data_format": {
            "ignore": true,
            "description": "Format data is in.  This is not used client-side because it's always a timestamp client side."
        },
        min: { ignore: true },
        max: { ignore: true },
        year_range: { ignore: true }
    };
    return et2_date_ro;
}(et2_core_valueWidget_1.et2_valueWidget));
exports.et2_date_ro = et2_date_ro;
et2_core_widget_1.et2_register_widget(et2_date_ro, ["date_ro", "date-time_ro", "date-since", "date-time_today", "time_or_date", "date-timeonly_ro"]);
/**
 * Widget for selecting a date range
 */
var et2_date_range = /** @class */ (function (_super) {
    __extends(et2_date_range, _super);
    /**
     * Constructor
     */
    function et2_date_range(_parent, _attrs, _child) {
        var _this = 
        // Call the inherited constructor
        _super.call(this, _parent, _attrs, et2_core_inheritance_1.ClassWithAttributes.extendAttributes(et2_date_range._attributes, _child || {})) || this;
        _this.div = jQuery(document.createElement('div'))
            .attr({ class: 'et2_date_range' });
        _this.from = null;
        _this.to = null;
        _this.select = null;
        // Set domid
        _this.set_id(_this.id);
        _this.setDOMNode(_this.div[0]);
        _this._createWidget();
        _this.set_relative(_this.options.relative || false);
        return _this;
    }
    et2_date_range.prototype._createWidget = function () {
        var widget = this;
        this.from = et2_core_widget_1.et2_createWidget('date', {
            id: this.id + '[from]',
            blur: egw.lang('From'),
            onchange: function () { widget.to.set_min(widget.from.getValue()); }
        }, this);
        this.to = et2_core_widget_1.et2_createWidget('date', {
            id: this.id + '[to]',
            blur: egw.lang('To'),
            onchange: function () { widget.from.set_max(widget.to.getValue()); }
        }, this);
        this.select = et2_core_widget_1.et2_createWidget('select', {
            id: this.id + '[relative]',
            select_options: et2_date_range.relative_dates,
            empty_label: this.options.blur || 'All'
        }, this);
        this.select.loadingFinished();
    };
    /**
     * Function which allows iterating over the complete widget tree.
     * Overridden here to avoid problems with children when getting value
     *
     * @param _callback is the function which should be called for each widget
     * @param _context is the context in which the function should be executed
     * @param _type is an optional parameter which specifies a class/interface
     * 	the elements have to be instanceOf.
     */
    et2_date_range.prototype.iterateOver = function (_callback, _context, _type) {
        if (typeof _type == "undefined") {
            _type = et2_core_widget_1.et2_widget;
        }
        if (this.isInTree() && this.instanceOf(_type)) {
            _callback.call(_context, this);
        }
    };
    /**
     * Toggles relative or absolute dates
     *
     * @param {boolean} _value
     */
    et2_date_range.prototype.set_relative = function (_value) {
        this.options.relative = _value;
        if (this.options.relative) {
            jQuery(this.from.getDOMNode()).hide();
            jQuery(this.to.getDOMNode()).hide();
        }
        else {
            jQuery(this.select.getDOMNode()).hide();
        }
    };
    et2_date_range.prototype.set_value = function (value) {
        // @ts-ignore
        if (!value || typeof value == 'null') {
            this.select.set_value('');
            this.from.set_value(null);
            this.to.set_value(null);
        }
        // Relative
        if (value && typeof value === 'string') {
            this._set_relative_value(value);
        }
        else if (value && typeof value.from === 'undefined' && value[0]) {
            value = {
                from: value[0],
                to: value[1] || new Date().valueOf() / 1000
            };
        }
        else if (value && value.from && value.to) {
            this.from.set_value(value.from);
            this.to.set_value(value.to);
        }
    };
    et2_date_range.prototype.getValue = function () {
        return this.options.relative ?
            this.select.getValue() :
            { from: this.from.getValue(), to: this.to.getValue() };
    };
    et2_date_range.prototype._set_relative_value = function (_value) {
        if (this.options.relative) {
            jQuery(this.select.getDOMNode()).show();
        }
        // Show description
        this.select.set_value(_value);
        var tempDate = new Date();
        var today = new Date(tempDate.getFullYear(), tempDate.getMonth(), tempDate.getDate(), 0, -tempDate.getTimezoneOffset(), 0);
        // Use strings to avoid references
        this.from.set_value(today.toJSON());
        this.to.set_value(today.toJSON());
        var relative = null;
        for (var index in et2_date_range.relative_dates) {
            if (et2_date_range.relative_dates[index].value === _value) {
                relative = et2_date_range.relative_dates[index];
                break;
            }
        }
        if (relative) {
            var dates = ["from", "to"];
            var value = today.toJSON();
            for (var i = 0; i < dates.length; i++) {
                var date = dates[i];
                if (typeof relative[date] == "function") {
                    value = relative[date](new Date(value));
                }
                else {
                    value = this[date]._relativeDate(relative[date]);
                }
                this[date].set_value(value);
            }
        }
    };
    et2_date_range._attributes = {
        value: {
            "type": "any",
            "description": "An object with keys 'from' and 'to' for absolute ranges, or a relative range string"
        },
        relative: {
            name: 'Relative',
            type: 'boolean',
            description: 'Is the date range relative (this week) or absolute (2016-02-15 - 2016-02-21).  This will affect the value returned.'
        }
    };
    // Class Constants
    et2_date_range.relative_dates = [
        // Start and end are relative offsets, see et2_date.set_min()
        // or Date objects
        {
            value: 'Today',
            label: egw.lang('Today'),
            from: function (date) { return date; },
            to: function (date) { return date; }
        },
        {
            label: egw.lang('Yesterday'),
            value: 'Yesterday',
            from: function (date) {
                date.setUTCDate(date.getUTCDate() - 1);
                return date;
            },
            to: ''
        },
        {
            label: egw.lang('This week'),
            value: 'This week',
            from: function (date) { return egw.week_start(date); },
            to: function (date) {
                date.setUTCDate(date.getUTCDate() + 6);
                return date;
            }
        },
        {
            label: egw.lang('Last week'),
            value: 'Last week',
            from: function (date) {
                var d = egw.week_start(date);
                d.setUTCDate(d.getUTCDate() - 7);
                return d;
            },
            to: function (date) {
                date.setUTCDate(date.getUTCDate() + 6);
                return date;
            }
        },
        {
            label: egw.lang('This month'),
            value: 'This month',
            from: function (date) {
                date.setUTCDate(1);
                return date;
            },
            to: function (date) {
                date.setUTCMonth(date.getUTCMonth() + 1);
                date.setUTCDate(0);
                return date;
            }
        },
        {
            label: egw.lang('Last month'),
            value: 'Last month',
            from: function (date) {
                date.setUTCMonth(date.getUTCMonth() - 1);
                date.setUTCDate(1);
                return date;
            },
            to: function (date) {
                date.setUTCMonth(date.getUTCMonth() + 1);
                date.setUTCDate(0);
                return date;
            }
        },
        {
            label: egw.lang('Last 3 months'),
            value: 'Last 3 months',
            from: function (date) {
                date.setUTCMonth(date.getUTCMonth() - 2);
                date.setUTCDate(1);
                return date;
            },
            to: function (date) {
                date.setUTCMonth(date.getUTCMonth() + 3);
                date.setUTCDate(0);
                return date;
            }
        },
        /*
        'This quarter'=> array(0,0,0,0,  0,0,0,0),      // Just a marker, needs special handling
        'Last quarter'=> array(0,-4,0,0, 0,-4,0,0),     // Just a marker
        */
        {
            label: egw.lang('This year'),
            value: 'This year',
            from: function (d) {
                d.setUTCMonth(0);
                d.setUTCDate(1);
                return d;
            },
            to: function (d) {
                d.setUTCMonth(11);
                d.setUTCDate(31);
                return d;
            }
        },
        {
            label: egw.lang('Last year'),
            value: 'Last year',
            from: function (d) {
                d.setUTCMonth(0);
                d.setUTCDate(1);
                d.setUTCYear(d.getUTCYear() - 1);
                return d;
            },
            to: function (d) {
                d.setUTCMonth(11);
                d.setUTCDate(31);
                d.setUTCYear(d.getUTCYear() - 1);
                return d;
            }
        }
        /* Still needed?
        '2 years ago' => array(-2,0,0,0, -1,0,0,0),
        '3 years ago' => array(-3,0,0,0, -2,0,0,0),
        */
    ];
    return et2_date_range;
}(et2_core_inputWidget_1.et2_inputWidget));
exports.et2_date_range = et2_date_range;
et2_core_widget_1.et2_register_widget(et2_date_range, ["date-range"]);
//# sourceMappingURL=et2_widget_date.js.map