Ctrl K
ComunidadGuías…

tine20/Calendar/js/PagingToolbar.js

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
/* 
 * Tine 2.0
 * 
 * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
 * @author      Cornelius Weiss <c.weiss@metaways.de>
 * @copyright   Copyright (c) 2007-2008 Metaways Infosystems GmbH (http://www.metaways.de)
 */

Ext.ns('Tine.Calendar');

Tine.Calendar.PagingToolbar = Ext.extend(Ext.Toolbar, {
    /**
     * @cfg {Date} dtstart
     */
    dtStart: null,
    /**
     * @cfg {String} view
     */
    view: 'day',
    /**
     * @private periodPicker
     */
    periodPicker: null,
    /**
     * @cfg {Boolean} showReloadBtn
     */    
    showReloadBtn: true,
    /**
     * @cfg {Boolean} showTodayBtn
     */ 
    showTodayBtn: true,
    /**
     * shows if the periodpicker is active
     * @type boolean
     */
    periodPickerActive: null,
    
    /**
     * @private
     */
    initComponent: function() {
        this.addEvents(
            /**
             * @event change
             * Fired whenever a viewstate changes
             * @param {Tine.Calendar.PagingToolbar} this
             * @param {String} activeView
             * @param {Array} period
             */
            'change',
            /**
             * @event refresh
             * Fired when user request view freshresh
             * @param {Tine.Calendar.PagingToolbar} this
             * @param {String} activeView
             * @param {Array} period
             */
            'refresh'
        );
        if (! Ext.isDate(this.dtStart)) {
            this.dtStart = new Date().clearTime();
        }
        
        this.periodPicker = new Tine.Calendar.PagingToolbar[Ext.util.Format.capitalize(this.view) + 'PeriodPicker']({
            tb: this,
            listeners: {
                scope: this,
                change: function(picker, view, period) {
                    this.dtStart = period.from.clearTime(true);
                    this.fireEvent('change', this, view, period);
                },
                menushow: function(){this.periodPickerActive = true; },
                menuhide: function(){this.periodPickerActive = false;}
            }
        });
        
        Tine.Calendar.PagingToolbar.superclass.initComponent.call(this);
        this.bind(this.store);
    },
    
    /**
     * @private
     */
    onRender: function(ct, position) {
        Tine.Calendar.PagingToolbar.superclass.onRender.call(this, ct, position);
        this.prevBtn = this.addButton({
            tooltip: Ext.PagingToolbar.prototype.prevText,
            iconCls: "x-tbar-page-prev",
            handler: this.onClick.createDelegate(this, ["prev"])
        });
        this.addSeparator();
        this.periodPicker.render();
        this.addSeparator();
        this.nextBtn = this.addButton({
            tooltip: Ext.PagingToolbar.prototype.nextText,
            iconCls: "x-tbar-page-next",
            handler: this.onClick.createDelegate(this, ["next"])
        });
        
        if(this.showTodayBtn || this.showReloadBtn) this.addSeparator();
        
        if(this.showTodayBtn) {
            this.todayBtn = this.addButton({
                text: Ext.DatePicker.prototype.todayText,
                iconCls: 'cal-today-action',
                handler: this.onClick.createDelegate(this, ["today"])
            });
        }

        if(this.showReloadBtn) {
            this.loading = this.addButton({
                tooltip: Ext.PagingToolbar.prototype.refreshText,
                iconCls: "x-tbar-loading",
                handler: this.onClick.createDelegate(this, ["refresh"])
            });
        }
        
        this.addFill();
        if (this.additionalItems) {
            this.addButton(this.additionalItems);
        }
        
        if(this.isLoading){
            this.loading.disable();
        }
    },
    
    /**
     * @private
     * @param {String} which
     */
    onClick: function(which) {
        switch(which) {
            case 'today':
            case 'next':
            case 'prev':
                this.periodPicker[which]();
                this.fireEvent('change', this, this.activeView, this.periodPicker.getPeriod());
                break;
            case 'refresh':
                this.fireEvent('refresh', this, this.activeView, this.periodPicker.getPeriod());
                break;
        }
    },
    
    /**
     * returns requested period
     * @return {Array}
     */
    getPeriod: function() {
        return this.periodPicker.getPeriod();
    },
    
    // private
    beforeLoad : function(){
        this.isLoading = true;
        
        if(this.rendered && this.loading) {
            this.loading.disable();
        }
    },
    
    // private
    onLoad : function(store, r, o){
        this.isLoading = false;
        
        if(this.rendered && this.loading) {
            this.loading.enable();
        }
    },

    /**
     * Unbinds the paging toolbar from the specified {@link Ext.data.Store}
     * @param {Ext.data.Store} store The data store to unbind
     */
    unbind : function(store){
        store = Ext.StoreMgr.lookup(store);
        store.un("beforeload", this.beforeLoad, this);
        store.un("load", this.onLoad, this);
        //store.un("loadexception", this.onLoadError, this);
        this.store = undefined;
    },

    /**
     * Binds the paging toolbar to the specified {@link Ext.data.Store}
     * @param {Ext.data.Store} store The data store to bind
     */
    bind : function(store){
        store = Ext.StoreMgr.lookup(store);
        store.on("beforeload", this.beforeLoad, this);
        store.on("load", this.onLoad, this);
        //store.on("loadexception", this.onLoadError, this);
        this.store = store;
    },

    /**
     * just needed when inserted in an eventpickercombobox
     */
    bindStore: function() {},
    
    // private
    onDestroy : function(){
        if(this.store){
            this.unbind(this.store);
        }
        Tine.Calendar.PagingToolbar.superclass.onDestroy.call(this);
    }
});

/**
 * @class Tine.Calendar.PagingToolbar.AbstractPeriodPicker
 * @extends Ext.util.Observable
 * @constructor
 * @param {Object} config
 */
Tine.Calendar.PagingToolbar.AbstractPeriodPicker = function(config) {
    Ext.apply(this, config);
    this.addEvents(
        /**
         * @event change
         * Fired whenever a period changes
         * @param {Tine.Calendar.PagingToolbar.AbstractPeriodPicker} this
         * @param {String} corresponding view
         * @param {Array} period
         */
        'change'
    );
    Tine.Calendar.PagingToolbar.AbstractPeriodPicker.superclass.constructor.call(this);
    
    this.update(this.tb.dtStart);
    this.init();
};
Ext.extend(Tine.Calendar.PagingToolbar.AbstractPeriodPicker, Ext.util.Observable, {
    /**
     * period NOTE: might not fit to current range on view changes!
     */
    period: null,

    init:       function() {},
    hide:       function() {this.button.hide();},
    show:       function() {this.button.show();},
    update:     function(period) {},
    render:     function() {},
    prev:       function() {},
    next:       function() {},
    today:      function() {this.update(new Date().clearTime());},
    getPeriod:  function() {}
});

/**
 * @class Tine.Calendar.PagingToolbar.DayPeriodPicker
 * @extends Tine.Calendar.PagingToolbar.AbstractPeriodPicker
 * @constructor
 */
Tine.Calendar.PagingToolbar.DayPeriodPicker = Ext.extend(Tine.Calendar.PagingToolbar.AbstractPeriodPicker, {
    init: function() {
        this.button = new Ext.Button({
            text: this.tb.dtStart.format(Ext.DatePicker.prototype.format),
            //hidden: this.tb.activeView != 'day',
            menu: new Ext.menu.DateMenu({
                listeners: {
                    scope: this,
                    
                    select: function(field) {
                        if (typeof(field.getValue) == 'function') {
                            this.update(field.getValue());
                            this.fireEvent('change', this, 'day', this.getPeriod());
                        }
                    }
                }
            })
        });
    },
    update: function(period) {
        this.dtStart = _.get(period, 'from', period).clearTime(true);
        if (this.button && this.button.rendered) {
            this.button.setText(this.dtStart.format(Ext.DatePicker.prototype.format));
        }
    },
    render: function() {
        this.button = this.tb.addButton(this.button);
    },
    next: function() {
        this.dtStart = this.dtStart.add(Date.DAY, 1);
        this.update(this.dtStart);
    },
    prev: function() {
        this.dtStart = this.dtStart.add(Date.DAY, -1);
        this.update(this.dtStart);
    },
    getPeriod: function() {
        var from = Date.parseDate(this.dtStart.format('Y-m-d') + ' 00:00:00', Date.patterns.ISO8601Long);
        return {
            from: from,
            until: from.add(Date.DAY, 1)/*.add(Date.SECOND, -1)*/
        };
    }
});

/**
 * @class Tine.Calendar.PagingToolbar.WeekPeriodPicker
 * @extends Tine.Calendar.PagingToolbar.AbstractPeriodPicker
 * @constructor
 */
Tine.Calendar.PagingToolbar.WeekPeriodPicker = Ext.extend(Tine.Calendar.PagingToolbar.AbstractPeriodPicker, {
    datepickerMenu: null,
    datepickerButton: null,
    wkField: null,

    init: function() {
        this.label = new Ext.form.Label({
            text: Tine.Tinebase.appMgr.get('Calendar').i18n._('Week'),
            style: 'padding-right: 3px'
        });

        this.wkField = new Ext.form.TextField({
            value: this.tb.dtStart.getWeekOfYear(),
            cls: "x-tbar-page-number",
            listeners: {
                scope: this,
                specialkey: this.onSelect,
                blur: this.onSelect
            }
        });

        this.yearField = new Ext.form.Label({
            text: this.tb.dtStart.format('o'),
            style: 'padding-left: 3px'
        });


        this.datepickerMenu = new Ext.menu.DateMenu({
            value: this.tb.dtStart,
            hideOnClick: true,
            focusOnSelect: true,
            plugins: [new Ext.ux.DatePickerWeekPlugin({
                weekHeaderString: Tine.Tinebase.appMgr.get('Calendar').i18n._('WK')
            })],
            listeners: {
                scope: this,
                'select': function (picker, date) {
                    var oldPeriod = this.getPeriod();
                    this.update(date);

                    if (this.getPeriod().from.getElapsed(oldPeriod.from)) {
                        this.fireEvent('change', this, 'week', this.getPeriod());
                    }
                }
            }
        });

        this.datepickerButton = new Ext.Button({
            iconCls: 'cal-sheet-view-type'
        });

        this.datepickerButton.on('click', function () {
            this.datepickerMenu.show(this.datepickerButton.el);
        }.createDelegate(this));
    },
    onSelect: function(field, e) {
        if (e && e.getKey() == e.ENTER) {
            return field.blur();
        }
        var diff = field.getValue() - this.dtStart.getWeekOfYear() - parseInt(this.dtStart.getDay() < 1 ? 1 : 0, 10);
        if (diff !== 0) {
            this.update(this.dtStart.add(Date.DAY, diff * 7));
            this.fireEvent('change', this, 'week', this.getPeriod());
        }
        
    },
    update: function(period) {
        let dtStart = _.get(period, 'from', period).clearTime(true);

        // const state = Ext.state.Manager.get('cal-pgtb-pp-wkbtn');
        let wkStartDiff = 0;
        if (this.tb.periodBtn) {
            const state = this.tb.periodBtn.getState();
            wkStartDiff = state.startIdx - Tine.Calendar.PagingToolbar.WeekPeriodPicker.Button.prototype.beforeDays;
        }

        const startDay = Ext.DatePicker.prototype.startDay;
        
        // recalculate dtstart according to WeekPeriodPicker.Button
        this.dtStart = dtStart.add(Date.DAY, -1 * (7+dtStart.getDay() - startDay - wkStartDiff)%7);
        if (this.getPeriod().until < dtStart) {
            this.dtStart = this.dtStart.add(Date.DAY, 7);
        }
        
        if (this.wkField && this.wkField.rendered) {
            // NOTE: '+1' is to ensure we display the ISO8601 based week where weeks always start on monday!
            var wkStart = this.dtStart.add(Date.DAY, dtStart.getDay() < 1 ? 1 : 0)
                .add(Date.DAY, -1*wkStartDiff);
            
            this.wkField.setValue(parseInt(wkStart.getWeekOfYear(), 10));
            this.yearField.setText(this.dtStart.format('o'));
        }
    },
    render: function() {
        this.tb.addField(this.label);
        this.tb.addField(this.wkField);
        this.tb.addField(this.yearField);
        this.tb.addField(this.datepickerButton);
    },
    hide: function() {
        this.label.hide();
        this.wkField.hide();
        this.yearField.hide();
        this.datepickerButton.hide();
    },
    show: function() {
        this.label.show();
        this.wkField.show();
        this.yearField.show();
        this.datepickerButton.show();
    },
    next: function() {
        this.dtStart = this.dtStart.add(Date.DAY, 7);
        this.update(this.dtStart);
    },
    prev: function() {
        this.dtStart = this.dtStart.add(Date.DAY, -7);
        this.update(this.dtStart);
    },
    getPeriod: function() {
        const state = this.tb.periodBtn ? this.tb.periodBtn.getState() : {
            endIdx: 7,
            startIdx: 1,
        };
        // const state = Ext.state.Manager.get('cal-pgtb-pp-wkbtn');
        return {
            from: this.dtStart.clone(),
            until: this.dtStart.add(Date.DAY, state.endIdx - state.startIdx+1)
        };
    }
});

Tine.Calendar.PagingToolbar.WeekPeriodPicker.Button = Ext.extend(Ext.SplitButton, {
    // override via prototype or config
    beforeDays: 1,
    numDays: 10,
    
    stateful: true,
    stateId: 'cal-pgtb-pp-wkbtn',
    
    initComponent: function() {
        this.app = Tine.Tinebase.appMgr.get('Calendar');

        const state = Ext.state.Manager.get(this.stateId);
        const wkStartDay = _.get(state, 'wkStart', Ext.DatePicker.prototype.startDay);
        const selectionStartIdx = _.get(state, 'startIdx', this.beforeDays+wkStartDay-1);
        const selectionEndIdx = _.get(state, 'endIdx',selectionStartIdx + 6);
        
        this.startDay = (wkStartDay+7-this.beforeDays)%7;
        
        this.dayBtns = [];
        // @TODO: if week is not standard, have a marker in btn?
        for (let i=0,dayNum=this.startDay; i<this.numDays; i++,dayNum++) {
            this.dayBtns.push(new Ext.Button({
                pressed: i >= selectionStartIdx && i <= selectionEndIdx,
                dayIdx: i,
                dayNum: dayNum,
                text: Date.dayNames[dayNum%7].substr(0,2),
                enableToggle: true,
                scope: this,
                handler: this.onDayBtnPress
            }));
        }
        
        this.menu = new Ext.menu.Menu({ 
            items: [new Ext.Toolbar({
                cls: 'cal-wkperiod-config-menu',
                items: [].concat(this.dayBtns, {xtype: 'tbtext', width: 40}, 
                    {text: i18n._hidden('OK'), variant: 'primary', handler: () => {this.menu.hide()}})
        })]});
        
        this.menu.on('hide', this.onMenuHide, this);
        this.supr().initComponent.call(this);
    },

    onMenuHide: function() {
        const state = Ext.state.Manager.get(this.stateId);
        if (JSON.stringify(state) !== JSON.stringify(this.getState())) {
            this.saveState();
            this.fireEvent('change', this, state);
        }
    },
    onDayBtnPress: function(btn) {
        const selected = _.filter(this.dayBtns, {pressed: true});
        
        if (! btn.pressed) {
            // deselect/reduce
            const bellow = _.filter(selected, (cmp) => {return cmp.dayIdx < btn.dayIdx});
            const above = _.filter(selected, (cmp) => { return cmp.dayIdx > btn.dayIdx });
            const toReduce = bellow.length < above.length ? bellow : above;
            _.each(toReduce, (btn) => { btn.toggle(false, false) });
            if (bellow.length + above.length < 3) {
                btn.toggle(true, false);
            }
        } else {
            // select/expand
            let lastIdx = selected[0].dayIdx;
            _.each(selected, (btn) => {
                for(let idx=lastIdx+1; idx<btn.dayIdx; idx++) {
                    this.dayBtns[idx].toggle(true, false);
                }
                lastIdx = btn.dayIdx;
            })
        }
    },
    
    getState: function() {
        const state = {
            startIdx: _.find(this.dayBtns, {pressed: true}).dayIdx,
            endIdx: _.findLast(this.dayBtns, {pressed: true}).dayIdx
        }
        
        // normalise
        if (state.startIdx-7 >= 0) {
            state.startIdx = state.startIdx-7;
            state.endIdx = state.endIdx-7;
        }
        return state;
    },

    onRender : function(){
        Tine.Calendar.PagingToolbar.WeekPeriodPicker.Button.superclass.onRender.apply(this, arguments);
        // have less optical focus
        this.btnEl.setStyle({border: "none"});
    },
});
/**
 * @class Tine.Calendar.PagingToolbar.MonthPeriodPicker
 * @extends Tine.Calendar.PagingToolbar.AbstractPeriodPicker
 * @constructor
 */
Tine.Calendar.PagingToolbar.MonthPeriodPicker = Ext.extend(Tine.Calendar.PagingToolbar.AbstractPeriodPicker, {
    init: function() {
        this.dateMenu = new Ext.menu.DateMenu({
            hideMonthPicker: Ext.DatePicker.prototype.hideMonthPicker.createSequence(function() {
                if (this.monthPickerActive) {
                    this.monthPickerActive = false;
                    
                    this.value = this.activeDate;
                    this.fireEvent('select', this, this.value);
                }
            }),
            listeners: {
                scope: this,
                select: function(field) {
                    if (typeof(field.getValue) == 'function') {
                        this.update(field.getValue());
                        this.fireEvent('change', this, 'month', this.getPeriod());
                    }
                }
            }
        });
        
        this.button = new Ext.Button({
            minWidth: 130,
            text: Ext.DatePicker.prototype.monthNames[this.tb.dtStart.getMonth()] + this.tb.dtStart.format(' Y'),
            //hidden: this.tb.activeView != 'month',
            menu: this.dateMenu,
            listeners: {
                scope: this,
                menushow: function(btn, menu) {
                    menu.picker.showMonthPicker();
                    menu.picker.monthPickerActive = true;
                    this.fireEvent('menushow');
                },
                menuhide: function(btn, menu) {
                    menu.picker.monthPickerActive = false;
                    this.fireEvent('menuhide');
                }
            }
        });
    },
    update: function(period) {
        this.dtStart = _.get(period, 'from', period).clearTime(true);
        if (this.button && this.button.rendered) {
            var monthName = Ext.DatePicker.prototype.monthNames[this.dtStart.getMonth()];
            this.button.setText(monthName + this.dtStart.format(' Y'));
            this.dateMenu.picker.setValue(this.dtStart.clone());
        }
    },
    render: function() {
        this.button = this.tb.addButton(this.button);
    },
    next: function() {
        this.dtStart = this.dtStart.add(Date.MONTH, 1);
        this.update(this.dtStart);
    },
    prev: function() {
        this.dtStart = this.dtStart.add(Date.MONTH, -1);
        this.update(this.dtStart);
    },
    getPeriod: function() {
        var from = Date.parseDate(this.dtStart.format('Y-m') + '-01 00:00:00', Date.patterns.ISO8601Long);
        return {
            from: from,
            until: from.add(Date.MONTH, 1)/*.add(Date.SECOND, -1)*/
        };
    }
});

/**
 * @class Tine.Calendar.PagingToolbar.YearPeriodPicker
 * @extends Tine.Calendar.PagingToolbar.AbstractPeriodPicker
 * @constructor
 */
Tine.Calendar.PagingToolbar.YearPeriodPicker = Ext.extend(Tine.Calendar.PagingToolbar.AbstractPeriodPicker, {
    init: function() {
        this.label = new Ext.form.Label({
            text: Tine.Tinebase.appMgr.get('Calendar').i18n._('Year'),
            style: 'padding-right: 3px'
        });
        this.field = new Ext.form.TextField({
            value: this.tb.dtStart.format('Y'),
            width: 40,
            cls: "x-tbar-page-number",
            listeners: {
                scope: this,
                specialkey: this.onSelect,
                blur: this.onSelect
            }
        });
    },
    onSelect: function(field, e) {
        if (e && e.getKey() == e.ENTER) {
            return field.blur();
        }
        var diff = field.getValue() - this.dtStart.format('Y'); 
        if (diff !== 0) {
            this.update(this.dtStart.add(Date.YEAR, diff ))
            this.fireEvent('change', this, 'year', this.getPeriod());
        }
        
    },
    update: function(period) {
        this.dtStart =  _.get(period, 'from', period).clearTime(true);
        if (this.field && this.field.rendered) {
            this.field.setValue(this.dtStart.format('Y'));
        }
    },
    render: function() {
        this.tb.addField(this.label);
        this.tb.addField(this.field);
    },
    hide: function() {
        this.label.hide();
        this.field.hide();
    },
    show: function() {
        this.label.show();
        this.field.show();
    },
    next: function() {
        this.dtStart = this.dtStart.add(Date.YEAR, 1);
        this.update(this.dtStart);
    },
    prev: function() {
        this.dtStart = this.dtStart.add(Date.YEAR, -1);
        this.update(this.dtStart);
    },
    getPeriod: function() {
        var from = Date.parseDate(this.dtStart.format('Y') + '-01-01 00:00:00', Date.patterns.ISO8601Long);
        return {
            from: from,
            until: from.add(Date.YEAR, 1)
        };
    }
});

/**
 * @class Tine.Calendar.PagingToolbar.CustomPeriodPicker
 * @extends Tine.Calendar.PagingToolbar.AbstractPeriodPicker
 * @constructor
 */
Tine.Calendar.PagingToolbar.CustomPeriodPicker = Ext.extend(Tine.Calendar.PagingToolbar.AbstractPeriodPicker, {

    init: function() {
        this.tb.showTodayBtn = false;

        this.fromLabel = new Ext.form.Label({
            text: Tine.Tinebase.appMgr.get('Calendar').i18n._('From'),
            style: 'padding-right: 3px'
        });

        this.fromPicker = new Ext.ux.form.DateTimeField ({
            style: 'margin-top: 2px',
            value: _.get(this, 'tb.period.from', this.tb.startDate) || new Date().clearTime(),
            listeners: {
                scope: this,
                specialkey: this.onSelect,
                blur: this.onSelect
            }
        });

        this.untilLabel = new Ext.form.Label({
            text: Tine.Tinebase.appMgr.get('Calendar').i18n._('until'),
            style: 'padding-left: 10px; padding-right: 3px'
        });

        this.untilPicker = new Ext.ux.form.DateTimeField ({
            style: 'margin-top: 2px',
            value: _.get(this, 'tb.period.until', this.tb.startDate) || new Date().clearTime().add(Date.DAY, 5),
            listeners: {
                scope: this,
                specialkey: this.onSelect,
                blur: this.onSelect
            }
        });

        this.period = this.getPeriod();
    },
    onSelect: function(field, e) {
        if (e && e.getKey() === e.ENTER) {
            return field.blur();
        }

        let currentPeriod = this.period;
        Tine.Tinebase.common.assertComparable(currentPeriod);

        let period = this.getPeriod();
        Tine.Tinebase.common.assertComparable(period);
        if (String(currentPeriod) !== String(period)) {
            this.fireEvent('change', this, 'custom', period);
        }
    },
    update: function(periodStart, period) {
        let boundaries = ['from', 'until'];

        _.each(boundaries, (boundary) => {
            if (_.get(this, `${boundary}Picker`) && _.isDate(_.get(period, boundary))) {
                let date = period[boundary].clone();

                // constrain to other boundary
                let boundaryIdx = boundaries.indexOf(boundary);
                let otherBoundary = boundaries[(boundaryIdx+1)%2];
                let otherDate =  _.isDate(_.get(period, otherBoundary)) ?
                    _.get(period, otherBoundary) : new Date().clearTime();

                this[`${boundary}Picker`].setValue(
                    new Date(Math[boundaryIdx ? 'max' : 'min'](date, otherDate))
                );

                // save state
                _.set(this, `period.${boundary}`, _.get(period, boundary).clone());
            }
        });
    },
    render: function() {
        this.tb.addField(this.fromLabel);
        this.tb.addField(this.fromPicker);
        this.tb.addField(this.untilLabel);
        this.tb.addField(this.untilPicker);
    },
    hide: function() {
        this.fromLabel.hide();
        this.fromPicker.hide();
        this.untilLabel.hide();
        this.untilPicker.hide();
    },
    show: function() {
        this.fromLabel.show();
        this.fromPicker.show();
        this.untilLabel.show();
        this.untilPicker.show();
    },
    next: function() {
        let period = this.getPeriod();

        this.update({
            from: period.until,
            until: period.until.add(Date.MILLI,  period.until.getTime() - period.from.getTime())
                .add(Date.SECOND, period.until.format('Z') - period.from.format('Z'))
        });
    },
    prev: function() {
        let period = this.getPeriod();

        this.update({
            from: period.until.add(Date.MILLI, period.from.getTime() - period.until.getTime())
                .add(Date.SECOND, period.from.format('Z') - period.until.format('Z')),
            until: period.from
        });
    },
    getPeriod: function() {
        // let from = this.fromPicker.getValue() || new Date
        return {
            from: this.fromPicker.getValue().clone(),
            until: this.untilPicker.getValue().clone()
        };
    }
});