Calendar refactors:

- date_helper, which was an et2_date_widget, now just a function that can handle all the different date formats in calendar
 - holiday fetch & cache moved into its own file, useable from anywhere
This commit is contained in:
nathan 2022-04-29 14:37:15 -06:00
parent f54c7f40bb
commit 813cd6924e
8 changed files with 192 additions and 255 deletions

View File

@ -544,7 +544,6 @@ class calendar_ui
$cont['owner'] = $this->owner ? (is_array($this->owner) ? $this->owner : explode(',',$this->owner) ) : $cont['owner'];
$cont['year'] = (int)Api\DateTime::to($cont['date'],'Y');
$cont['holidays'] = $this->bo->read_holidays($cont['year']);
$readonlys = array();
$sel_options['status_filter'] = array(

View File

@ -276,16 +276,6 @@ export class CalendarApp extends EgwApp
this.sidebox_hooked_templates.push(this.sidebox_et2);
jQuery(_et2.DOMContainer).hide();
// Set client side holiday cache for this year
// @ts-ignore
if(et2_calendar_view)
{
// @ts-ignore
et2_calendar_view.holiday_cache[content.data.year] = content.data.holidays;
delete content.data.holidays;
delete content.data.year;
}
this._setup_sidebox_filters();
this.state = content.data;

View File

@ -17,16 +17,17 @@
import {et2_createWidget, et2_register_widget, WidgetConfig} from "../../api/js/etemplate/et2_core_widget";
import {et2_valueWidget} from "../../api/js/etemplate/et2_core_valueWidget";
import {et2_calendar_timegrid} from "./et2_widget_timegrid";
import {et2_calendar_view} from "./et2_widget_view";
import {et2_calendar_event} from "./et2_widget_event";
import {ClassWithAttributes} from "../../api/js/etemplate/et2_core_inheritance";
import {et2_date} from "../../api/js/etemplate/et2_widget_date";
import {et2_IDetachedDOM, et2_IResizeable} from "../../api/js/etemplate/et2_core_interfaces";
import {et2_no_init} from "../../api/js/etemplate/et2_core_common";
import {egw} from "../../api/js/jsapi/egw_global";
import {egwIsMobile} from "../../api/js/egw_action/egw_action_common.js";
import {egwIsMobile, sprintf} from "../../api/js/egw_action/egw_action_common.js";
import {CalendarApp} from "./app";
import {sprintf} from "../../api/js/egw_action/egw_action_common.js";
import {holidays} from "../../api/js/etemplate/Et2Date/Holidays";
import {et2_calendar_view} from "./et2_widget_view";
import flatpickr from "flatpickr";
import {formatDate} from "../../api/js/etemplate/Et2Date/Et2Date";
/**
* Class which implements the "calendar-timegrid" XET-Tag for displaying a single days
@ -69,8 +70,7 @@ export class et2_calendar_daycol extends et2_valueWidget implements et2_IDetache
private event_wrapper: JQuery;
private user_spacer: JQuery;
private all_day: JQuery;
private _date_helper : et2_date;
private registeredUID: string = null;
// Init to defaults, just in case - they will be updated from parent
@ -118,11 +118,6 @@ export class et2_calendar_daycol extends et2_valueWidget implements et2_IDetache
.appendTo(this.div);
this.setDOMNode(this.div[0]);
// Used for its date calculations - note this is a datetime, parent
// uses just a date
this._date_helper = et2_createWidget('date-time', {}, null);
this._date_helper.loadingFinished();
}
doLoadingFinished( )
@ -158,10 +153,6 @@ export class et2_calendar_daycol extends et2_valueWidget implements et2_IDetache
this.title = null;
this.user_spacer = null;
// date_helper has no parent, so we must explicitly remove it
this._date_helper.destroy();
this._date_helper = null;
egw.dataUnregisterUID(this.registeredUID,null,this);
}
@ -225,9 +216,9 @@ export class et2_calendar_daycol extends et2_valueWidget implements et2_IDetache
return this.date;
}
get date_helper(): et2_date
date_helper(value)
{
return this._date_helper;
return (<et2_calendar_view>this.getParent()).date_helper(value);
}
/**
@ -249,28 +240,16 @@ export class et2_calendar_daycol extends et2_valueWidget implements et2_IDetache
{
force_redraw = false;
}
if(!this.getParent() || !this.getParent().date_helper)
if(!this.getParent())
{
egw.debug('warn', 'Day col widget "' + this.id + '" is missing its parent.');
return false;
}
if(typeof _date === "object")
{
this.getParent().date_helper.set_value(_date);
}
else if(typeof _date === "string")
{
// Need a new date to avoid invalid month/date combinations when setting
// month then day. Use a string to avoid browser timezone.
this.getParent().date_helper.set_value(_date.substring(0,4)+'-'+(_date.substring(4,6))+'-'+_date.substring(6,8)+'T00:00:00Z');
}
this.date = new Date(this.getParent().date_helper.getValue());
this.date = (<et2_calendar_view>this.getParent()).date_helper(_date);
// Keep internal option in Ymd format, it gets passed around in this format
const new_date = "" + this.getParent().date_helper.get_year() +
sprintf("%02d", this.getParent().date_helper.get_month()) +
sprintf("%02d", this.getParent().date_helper.get_date());
const new_date = formatDate(this.date, {dateFormat: "Ymd"});
// Set label
if(!this.options.label)
@ -278,9 +257,9 @@ export class et2_calendar_daycol extends et2_valueWidget implements et2_IDetache
// Add timezone offset back in, or formatDate will lose those hours
const formatDate = new Date(this.date.valueOf() + this.date.getTimezoneOffset() * 60 * 1000);
this.title.html('<span class="long_date">'+jQuery.datepicker.formatDate('DD',formatDate)+
'</span><span class="short_date">'+jQuery.datepicker.formatDate('D',formatDate)+'</span>'+
jQuery.datepicker.formatDate('d',formatDate));
this.title.html('<span class="long_date">' + flatpickr.formatDate(formatDate, 'l') +
'</span><span class="short_date">' + flatpickr.formatDate(formatDate, 'D') + '</span>' +
flatpickr.formatDate(formatDate, 'd'));
}
this.title
.attr("data-date", new_date)
@ -472,7 +451,7 @@ export class et2_calendar_daycol extends et2_valueWidget implements et2_IDetache
);
// Holidays and birthdays
let holidays = await et2_calendar_view.get_holidays(this.options.date.substring(0, 4));
let fetched_holidays = await holidays(this.options.date.substring(0, 4));
const holiday_list = [];
let holiday_pref = (egw.preference('birthdays_as_events', 'calendar') || []);
if(typeof holiday_pref === 'string')
@ -490,27 +469,24 @@ export class et2_calendar_daycol extends et2_valueWidget implements et2_IDetache
const birthdays_as_events = egwIsMobile() || holiday_pref.indexOf('birthday') >= 0;
if(holidays && holidays[this.options.date])
if(fetched_holidays && fetched_holidays[this.options.date])
{
holidays = holidays[this.options.date];
for(let i = 0; i < holidays.length; i++)
fetched_holidays = fetched_holidays[this.options.date];
for(let i = 0; i < fetched_holidays.length; i++)
{
if (typeof holidays[i]['birthyear'] !== 'undefined')
if(typeof fetched_holidays[i]['birthyear'] !== 'undefined')
{
// Show birthdays as events on mobile or by preference
if(birthdays_as_events)
{
// Create event
this.getParent().date_helper.set_value(this.options.date.substring(0,4)+'-'+
(this.options.date.substring(4,6))+'-'+this.options.date.substring(6,8)+
'T00:00:00Z');
var event = et2_createWidget('calendar-event',{
id:'event_'+holidays[i].name,
var event = et2_createWidget('calendar-event', {
id: 'event_' + fetched_holidays[i].name,
value: {
title: holidays[i].name,
title: fetched_holidays[i].name,
whole_day: true,
whole_day_on_top: true,
start: new Date(this.getParent().date_helper.get_value()),
start: (<et2_calendar_view>this.getParent()).date_helper(this.options.date),
end: this.options.date,
owner: this.options.owner,
participants: this.options.owner,
@ -528,7 +504,7 @@ export class et2_calendar_daycol extends et2_valueWidget implements et2_IDetache
//If the birthdays are already displayed as event, don't
//show them in the caption
this.title.addClass('calendar_calBirthday');
holiday_list.push(holidays[i]['name']);
holiday_list.push(fetched_holidays[i]['name']);
}
}
else
@ -537,16 +513,13 @@ export class et2_calendar_daycol extends et2_valueWidget implements et2_IDetache
if(holidays_as_events)
{
// Create event
this.getParent().date_helper.set_value(this.options.date.substring(0,4)+'-'+
(this.options.date.substring(4,6))+'-'+this.options.date.substring(6,8)+
'T00:00:00Z');
var event = et2_createWidget('calendar-event',{
id:'event_'+holidays[i].name,
var event = et2_createWidget('calendar-event', {
id: 'event_' + fetched_holidays[i].name,
value: {
title: holidays[i].name,
title: fetched_holidays[i].name,
whole_day: true,
whole_day_on_top: true,
start: new Date(this.getParent().date_helper.get_value()),
start: (<et2_calendar_view>this.getParent()).date_helper(this.options.date),
end: this.options.date,
owner: this.options.owner,
participants: this.options.owner,
@ -562,13 +535,13 @@ export class et2_calendar_daycol extends et2_valueWidget implements et2_IDetache
else
{
this.title.addClass('calendar_calHoliday');
this.title.attr('data-holiday', holidays[i]['name']);
this.title.attr('data-holiday', fetched_holidays[i]['name']);
//If the birthdays are already displayed as event, don't
//show them in the caption
if (!this.options.display_holiday_as_event)
{
holiday_list.push(holidays[i]['name']);
holiday_list.push(fetched_holidays[i]['name']);
}
}
}

View File

@ -515,29 +515,30 @@ export class et2_calendar_event extends et2_valueWidget implements et2_IDetached
*/
_tooltip()
{
if (!this.div || !this.options.value || !this.options.value.app_id) return '';
if(!this.div || !this.options.value || !this.options.value.app_id)
{
return '';
}
const border = this.div.css('borderTopColor');
const bg_color = this.div.css('background-color');
const header_color = this.title.css('color');
const timespan = this._get_timespan(this.options.value);
const parent = this.getParent() instanceof et2_calendar_daycol ? (<et2_calendar_daycol>this.getParent()) : (<et2_calendar_planner_row>this.getParent());
const border = this.div.css('borderTopColor');
const bg_color = this.div.css('background-color');
const header_color = this.title.css('color');
const timespan = this._get_timespan(this.options.value);
const parent = this.getParent() instanceof et2_calendar_daycol ? (<et2_calendar_daycol>this.getParent()) : (<et2_calendar_planner_row>this.getParent());
parent.date_helper.set_value(this.options.value.start.valueOf ? new Date(this.options.value.start) : this.options.value.start);
const start = parent.date_helper.input_date.val();
parent.date_helper.set_value(this.options.value.end.valueOf ? new Date(this.options.value.end) : this.options.value.end);
const end = parent.date_helper.input_date.val();
const start = parent.date_helper(this.options.value.start);
const end = parent.date_helper(this.options.value.end);
const times = !this.options.value.multiday ?
'<span class="calendar_calEventLabel">' + this.egw().lang('Time') + '</span>:' + timespan :
'<span class="calendar_calEventLabel">' + this.egw().lang('Start') + '</span>:' + start + ' ' +
'<span class="calendar_calEventLabel">' + this.egw().lang('End') + '</span>:' + end;
let cat_label: (string | string[]) = '';
if (this.options.value.category)
{
const cat = et2_createWidget('select-cat', {'readonly': true}, this);
cat.set_value(this.options.value.category);
cat_label = this.options.value.category.indexOf(',') <= 0 ? cat.span.text() : [];
const times = !this.options.value.multiday ?
'<span class="calendar_calEventLabel">' + this.egw().lang('Time') + '</span>:' + timespan :
'<span class="calendar_calEventLabel">' + this.egw().lang('Start') + '</span>:' + start + ' ' +
'<span class="calendar_calEventLabel">' + this.egw().lang('End') + '</span>:' + end;
let cat_label : (string | string[]) = '';
if(this.options.value.category)
{
const cat = et2_createWidget('select-cat', {'readonly': true}, this);
cat.set_value(this.options.value.category);
cat_label = this.options.value.category.indexOf(',') <= 0 ? cat.span.text() : [];
if (typeof cat_label != 'string')
{
cat.span.children().each(function ()
@ -847,13 +848,11 @@ export class et2_calendar_event extends et2_valueWidget implements et2_IDetached
// Use dates as objects
if (typeof event.start !== 'object')
{
parent.date_helper.set_value(event.start);
event.start = new Date(parent.date_helper.getValue());
event.start = parent.date_helper(event.start);
}
if (typeof event.end !== 'object')
{
parent.date_helper.set_value(event.end);
event.end = new Date(parent.date_helper.getValue());
event.end = parent.date_helper(event.end)
}
// We need minutes for durations

View File

@ -15,7 +15,7 @@
/calendar/js/et2_widget_event.js;
*/
import {et2_register_widget, WidgetConfig} from "../../api/js/etemplate/et2_core_widget";
import {et2_createWidget, et2_register_widget, WidgetConfig} from "../../api/js/etemplate/et2_core_widget";
import {ClassWithAttributes} from "../../api/js/etemplate/et2_core_inheritance";
import {et2_calendar_view} from "./et2_widget_view";
import {et2_action_object_impl} from "../../api/js/etemplate/et2_core_DOMWidget";
@ -31,6 +31,8 @@ import {CalendarApp} from "./app";
import {sprintf} from "../../api/js/egw_action/egw_action_common.js";
import {et2_dataview_grid} from "../../api/js/etemplate/et2_dataview_view_grid";
import {et2_selectbox} from "../../api/js/etemplate/et2_widget_selectbox";
import {formatDate} from "../../api/js/etemplate/Et2Date/Et2Date";
import {holidays} from "../../api/js/etemplate/Et2Date/Holidays";
/**
* Class which implements the "calendar-planner" XET-Tag for displaying a longer
@ -1324,21 +1326,23 @@ export class et2_calendar_planner extends et2_calendar_view implements et2_IDeta
*/
async day_class_holiday(date, holiday_list, days?)
{
if(!date) return '';
if(!date)
{
return '';
}
// Holidays and birthdays
const holidays = await et2_calendar_view.get_holidays(date.getUTCFullYear());
const fetched = await holidays(date.getUTCFullYear());
var day_class = '';
// Pass a string rather than the date object, to make sure it doesn't get changed
this.date_helper.set_value(date.toJSON());
var date_key = ''+this.date_helper.get_year() + sprintf('%02d',this.date_helper.get_month()) + sprintf('%02d',this.date_helper.get_date());
if (holidays && holidays[date_key])
let date_key = formatDate(this.date_helper(date.toJSON()), {dateFormat: "Ymd"});
if(fetched && fetched[date_key])
{
const dates = holidays[date_key];
const dates = fetched[date_key];
for(var i = 0; i < dates.length; i++)
{
if (typeof dates[i]['birthyear'] !== 'undefined')
if(typeof dates[i]['birthyear'] !== 'undefined')
{
day_class += ' calendar_calBirthday ';
if(typeof days == 'undefined' || days <= 21)
@ -1805,8 +1809,7 @@ export class et2_calendar_planner extends et2_calendar_view implements et2_IDeta
var event_widget = planner.getWidgetById(event_data.widget_id);
if(event_widget)
{
event_widget._parent.date_helper.set_value(drop_date);
event_widget.options.value.start = new Date(event_widget._parent.date_helper.getValue());
event_widget.options.value.start = event_widget._parent.date_helper(drop_date);
// Leave the helper there until the update is done
var loading = ui.helper.clone().appendTo(ui.helper.parent());
@ -2393,6 +2396,7 @@ export class et2_calendar_planner extends et2_calendar_view implements et2_IDeta
var rel_time = 0;
var day_header = jQuery('.calendar_plannerScaleDay', this.headers);
let date;
// Simple math, the x is offset from start date
if(this.options.group_by !== 'month' && (
@ -2400,8 +2404,8 @@ export class et2_calendar_planner extends et2_calendar_view implements et2_IDeta
this.options.show_weekend || day_header.length === 0
))
{
rel_time = (new Date(this.options.end_date) - new Date(this.options.start_date))*rel_x/1000;
this.date_helper.set_value(this.options.start_date.toJSON());
rel_time = (new Date(this.options.end_date) - new Date(this.options.start_date)) * rel_x / 1000;
date = this.date_helper(this.options.start_date.toJSON());
}
// Not so simple math, need to account for missing days
else if(this.options.group_by !== 'month' && !this.options.show_weekend)
@ -2416,10 +2420,10 @@ export class et2_calendar_planner extends et2_calendar_view implements et2_IDeta
// Use day, and find time in that day
if(day && day.dataset && day.dataset.date)
{
this.date_helper.set_value(day.dataset.date);
rel_time = ((x - jQuery(day).position().left) / jQuery(day).outerWidth(true)) * 24*60;
this.date_helper.set_minutes(Math.round(rel_time/interval) * interval);
return new Date(this.date_helper.getValue());
date = this.date_helper(day.dataset.date);
rel_time = ((x - jQuery(day).position().left) / jQuery(day).outerWidth(true)) * 24 * 60;
date.setUTCMinutes(Math.round(rel_time / interval) * interval);
return date;
}
return false;
}
@ -2465,11 +2469,11 @@ export class et2_calendar_planner extends et2_calendar_view implements et2_IDeta
{
// Not sure where the extra -1 and +2 are coming from, but it makes it work out
// in FF & Chrome
rel_x = Math.min((x-row_widget.rows.offset().left-1)/(row_widget.rows.width()+2),1);
rel_x = Math.min((x - row_widget.rows.offset().left - 1) / (row_widget.rows.width() + 2), 1);
// 2678400 is the number of seconds in 31 days
rel_time = (2678400)*rel_x;
this.date_helper.set_value(row_widget.options.start_date.toJSON());
rel_time = (2678400) * rel_x;
date = this.date_helper(row_widget.options.start_date.toJSON());
}
else
{
@ -2478,9 +2482,9 @@ export class et2_calendar_planner extends et2_calendar_view implements et2_IDeta
}
if(rel_time < 0) return false;
this.date_helper.set_minutes(Math.round(rel_time / (60 * interval))*interval);
date.setUTCMinutes(Math.round(rel_time / (60 * interval)) * interval);
return new Date(this.date_helper.getValue());
return date;
}
/**

View File

@ -18,13 +18,13 @@
import {et2_createWidget, et2_register_widget, WidgetConfig} from "../../api/js/etemplate/et2_core_widget";
import {et2_valueWidget} from "../../api/js/etemplate/et2_core_valueWidget";
import {ClassWithAttributes} from "../../api/js/etemplate/et2_core_inheritance";
import {et2_date} from "../../api/js/etemplate/et2_widget_date";
import {et2_action_object_impl} from "../../api/js/etemplate/et2_core_DOMWidget";
import {et2_calendar_planner} from "./et2_widget_planner";
import {egw_getObjectManager, egwActionObject} from "../../api/js/egw_action/egw_action.js";
import {EGW_AI_DRAG_OUT, EGW_AI_DRAG_OVER} from "../../api/js/egw_action/egw_action_constants.js";
import {et2_IResizeable} from "../../api/js/etemplate/et2_core_interfaces";
import {egw} from "../../api/js/jsapi/egw_global";
import {et2_calendar_view} from "./et2_widget_view";
/**
* Class for one row of a planner
@ -50,7 +50,6 @@ export class et2_calendar_planner_row extends et2_valueWidget implements et2_IRe
private div: JQuery;
private title: JQuery;
private rows: JQuery;
private _date_helper: et2_date;
private _cached_rows: any[];
private _row_height = 20;
private _actionObject: egwActionObject;
@ -76,10 +75,6 @@ export class et2_calendar_planner_row extends et2_valueWidget implements et2_IRe
this.setDOMNode(this.div[0]);
// Used for its date calculations
this._date_helper = <et2_date>et2_createWidget('date-time', {}, null);
this._date_helper.loadingFinished();
this.set_start_date(this.options.start_date);
this.set_end_date(this.options.end_date);
@ -102,10 +97,6 @@ export class et2_calendar_planner_row extends et2_valueWidget implements et2_IRe
destroy( )
{
super.destroy();
// date_helper has no parent, so we must explicitly remove it
this._date_helper.destroy();
this._date_helper = null;
}
getDOMNode(_sender)
@ -494,9 +485,9 @@ export class et2_calendar_planner_row extends et2_valueWidget implements et2_IRe
}
}
get date_helper(): et2_date
date_helper(value)
{
return this._date_helper;
return (<et2_calendar_view>this.getParent()).date_helper(value);
}
/**
@ -625,13 +616,11 @@ export class et2_calendar_planner_row extends et2_valueWidget implements et2_IRe
const event = this._children[n].options.value || false;
if(typeof event.start !== 'object')
{
this._date_helper.set_value(event.start);
event.start = new Date(this._date_helper.getValue());
event.start = this.date_helper(event.start);
}
if(typeof event.end !== 'object')
{
this._date_helper.set_value(event.end);
event.end = new Date(this._date_helper.getValue());
event.end = this.date_helper(event.end);
}
if(typeof event['start_m'] === 'undefined')
{

View File

@ -26,8 +26,8 @@ import {et2_calendar_event} from "./et2_widget_event";
import {egw_getObjectManager, egwActionObject} from "../../api/js/egw_action/egw_action.js";
import {et2_compileLegacyJS} from "../../api/js/etemplate/et2_core_legacyJSFunctions";
import {Et2Dialog} from "../../api/js/etemplate/Et2Dialog/Et2Dialog";
import {sprintf} from "../../api/js/egw_action/egw_action_common.js";
import {EGW_AI_DRAG_OUT, EGW_AI_DRAG_OVER} from "../../api/js/egw_action/egw_action_constants.js";
import {formatDate} from "../../api/js/etemplate/Et2Date/Et2Date";
/**
* Class which implements the "calendar-timegrid" XET-Tag for displaying a span of days
@ -463,7 +463,8 @@ export class et2_calendar_timegrid extends et2_calendar_view implements et2_IDet
if(typeof dropEnd != 'undefined' && dropEnd)
{
var drop_date = dropEnd.date||false;
var drop_date = dropEnd.date || false;
let target_date;
var event_data = timegrid._get_event_info(ui.draggable);
var event_widget = timegrid.getWidgetById(event_data.widget_id);
@ -475,8 +476,8 @@ export class et2_calendar_timegrid extends et2_calendar_view implements et2_IDet
if(event_widget)
{
// Send full string to avoid rollover between months using set_month()
event_widget._parent.date_helper.set_value(
drop_date.substring(0,4)+'-'+drop_date.substring(4,6)+'-'+drop_date.substring(6,8)+
target_date = event_widget._parent.date_helper(
drop_date.substring(0, 4) + '-' + drop_date.substring(4, 6) + '-' + drop_date.substring(6, 8) +
'T00:00:00Z'
);
@ -484,20 +485,20 @@ export class et2_calendar_timegrid extends et2_calendar_view implements et2_IDet
// Make sure whole day events stay as whole day events by ignoring drop time
if(event_data.app == 'calendar' && event_widget.options.value.whole_day)
{
event_widget._parent.date_helper.set_hours(0);
event_widget._parent.date_helper.set_minutes(0);
target_date.setUTCHours(0);
target_date.setUTCMinutes(0);
}
else if (timegrid.options.granularity === 0)
{
// List, not time grid - keep time
event_widget._parent.date_helper.set_hours(event_widget.options.value.start.getUTCHours());
event_widget._parent.date_helper.set_minutes(event_widget.options.value.start.getUTCMinutes());
target_date.setUTCHours(event_widget.options.value.start.getUTCHours());
target_date.setUTCMinutes(event_widget.options.value.start.getUTCMinutes());
}
else
{
// Non-whole day events, and integrated apps, can change
event_widget._parent.date_helper.set_hours(dropEnd.whole_day ? 0 : dropEnd.hour||0);
event_widget._parent.date_helper.set_minutes(dropEnd.whole_day ? 0 : dropEnd.minute||0);
target_date.setUTCHours(dropEnd.whole_day ? 0 : dropEnd.hour || 0);
target_date.setUTCMinutes(dropEnd.whole_day ? 0 : dropEnd.minute || 0);
}
// Leave the helper there until the update is done
@ -531,7 +532,7 @@ export class et2_calendar_timegrid extends et2_calendar_view implements et2_IDet
// If it is an integrated infolog event we need to edit infolog entry
egw().json('stylite_infolog_calendar_integration::ajax_moveInfologEvent',
[event_data.app_id, event_widget._parent.date_helper.getValue()||false,duration],
[event_data.app_id, target_date || false, duration],
function() {loading.remove();}
).sendRequest(true);
}
@ -550,7 +551,7 @@ export class et2_calendar_timegrid extends et2_calendar_view implements et2_IDet
// Send the update
var _send = function(series_instance)
{
var start = new Date(event_widget._parent.date_helper.getValue());
var start = new Date(target_date);
egw().json('calendar.calendar_uiforms.ajax_moveEvent', [
button_id==='series' ? event_data.id : event_data.app_id,event_data.owner,
@ -1164,24 +1165,27 @@ export class et2_calendar_timegrid extends et2_calendar_view implements et2_IDet
_calculate_day_list( start_date, end_date, show_weekend)
{
var day_list = [];
let day_list = [];
if(!start_date || !end_date)
{
return day_list;
}
this.date_helper.set_value(end_date);
var end = this.date_helper.date.getTime();
var i = 1;
this.date_helper.set_value(new Date(start_date));
let end = this.date_helper(end_date).getTime();
let i = 1;
let start = this.date_helper(start_date);
do
{
if(show_weekend || !show_weekend && [0,6].indexOf(this.date_helper.date.getUTCDay()) === -1 || end_date === start_date)
if(show_weekend || !show_weekend && [0, 6].indexOf(this.date_helper.date.getUTCDay()) === -1 || end_date === start_date)
{
day_list.push(''+this.date_helper.get_year() + sprintf('%02d',this.date_helper.get_month()) + sprintf('%02d',this.date_helper.get_date()));
day_list.push(formatDate(start, {dateFormat: "Ymd"}));
}
this.date_helper.set_date(this.date_helper.get_date()+1);
start.setDate(start.getDate() + 1);
}
// Limit it to 14 days to avoid infinite loops in case something is mis-set,
// though the limit is more based on how wide the screen is
while(end >= this.date_helper.date.getTime() && i++ <= 14);
// Limit it to 14 days to avoid infinite loops in case something is mis-set,
// though the limit is more based on how wide the screen is
while(end >= start && i++ <= 14);
return day_list;
}
@ -2051,18 +2055,16 @@ export class et2_calendar_timegrid extends et2_calendar_view implements et2_IDet
}
// Format date
this.date_helper.set_year(start.date.substring(0,4));
this.date_helper.set_month(start.date.substring(4,6));
this.date_helper.set_date(start.date.substring(6,8));
let date = this.date_helper(start.date);
if(start.hour)
{
this.date_helper.set_hours(start.hour);
date.setUTCHours(start.hour);
}
if(start.minute)
{
this.date_helper.set_minutes(start.minute);
date.setUTCMinutes(start.minute);
}
start.date = this.date_helper.get_value();
start.date = date;
this.gridHover.css('cursor', 'ns-resize');
@ -2075,18 +2077,16 @@ export class et2_calendar_timegrid extends et2_calendar_view implements et2_IDet
var end = jQuery.extend({}, timegrid.gridHover[0].dataset);
if(end.date)
{
timegrid.date_helper.set_year(end.date.substring(0,4));
timegrid.date_helper.set_month(end.date.substring(4,6));
timegrid.date_helper.set_date(end.date.substring(6,8));
let date = timegrid.date_helper(end.date);
if(end.hour)
{
timegrid.date_helper.set_hours(end.hour);
date.setUTCHours(end.hour);
}
if(end.minute)
{
timegrid.date_helper.set_minutes(end.minute);
date.setUTCMinutes(end.minute);
}
timegrid.drag_create.end.date = timegrid.date_helper.get_value();
timegrid.drag_create.end.date = date;
}
try
{
@ -2113,18 +2113,16 @@ export class et2_calendar_timegrid extends et2_calendar_view implements et2_IDet
var end = jQuery.extend({}, this.gridHover[0].dataset);
if(end.date)
{
this.date_helper.set_year(end.date.substring(0,4));
this.date_helper.set_month(end.date.substring(4,6));
this.date_helper.set_date(end.date.substring(6,8));
let date = this.date_helper(end.date);
if(end.hour)
{
this.date_helper.set_hours(end.hour);
date.setUTCMinutes(end.hour);
}
if(end.minute)
{
this.date_helper.set_minutes(end.minute);
date.setUTCMinutes(end.minute);
}
end.date = this.date_helper.get_value();
end.date = date;
}
this.div.off('mousemove.dragcreate');
this.gridHover.css('cursor', '');

View File

@ -15,9 +15,8 @@
import {et2_createWidget, et2_widget, WidgetConfig} from "../../api/js/etemplate/et2_core_widget";
import {et2_valueWidget} from "../../api/js/etemplate/et2_core_valueWidget";
import {ClassWithAttributes} from "../../api/js/etemplate/et2_core_inheritance";
import {et2_date} from "../../api/js/etemplate/et2_widget_date";
import {et2_calendar_event} from "./et2_widget_event";
import {sprintf} from "../../api/js/egw_action/egw_action_common.js";
import {formatDate} from "../../api/js/etemplate/Et2Date/Et2Date";
/**
* Parent class for the various calendar views to reduce copied code
@ -47,7 +46,6 @@ export class et2_calendar_view extends et2_valueWidget
}
};
protected dataStorePrefix: string = 'calendar';
protected _date_helper: et2_date;
protected loader: JQuery;
protected div: JQuery;
protected now_div: JQuery;
@ -68,11 +66,6 @@ export class et2_calendar_view extends et2_valueWidget
// Call the inherited constructor
super(_parent, _attrs, ClassWithAttributes.extendAttributes(et2_calendar_view._attributes, _child || {}));
// Used for its date calculations
this._date_helper = <et2_date>et2_createWidget('date-time', {}, null);
this._date_helper.loadingFinished();
this.loader = jQuery('<div class="egw-loading-prompt-container ui-front loading"></div>');
this.now_div = jQuery('<div class="calendar_now"/>');
this.update_timer = null;
@ -90,10 +83,6 @@ export class et2_calendar_view extends et2_valueWidget
destroy() {
super.destroy();
// date_helper has no parent, so we must explicitly remove it
this._date_helper.destroy();
this._date_helper = null;
// Stop the invalidate timer
if(this.update_timer)
{
@ -175,22 +164,8 @@ export class et2_calendar_view extends et2_valueWidget
new_date = new Date();
}
// Use date widget's existing functions to deal
if(typeof new_date === "object" || typeof new_date === "string" && new_date.length > 8)
{
this._date_helper.set_value(new_date);
}
else if(typeof new_date === "string")
{
this._date_helper.set_year(new_date.substring(0, 4));
// Avoid overflow into next month, since we re-use date_helper
this._date_helper.set_date(1);
this._date_helper.set_month(new_date.substring(4, 6));
this._date_helper.set_date(new_date.substring(6, 8));
}
var old_date = this.options.start_date;
this.options.start_date = new Date(this._date_helper.getValue());
let old_date = this.options.start_date;
this.options.start_date = this.date_helper(new_date)
if(old_date !== this.options.start_date && this.isAttached())
{
@ -216,22 +191,9 @@ export class et2_calendar_view extends et2_valueWidget
{
new_date = new Date();
}
// Use date widget's existing functions to deal
if(typeof new_date === "object" || typeof new_date === "string" && new_date.length > 8)
{
this._date_helper.set_value(new_date);
}
else if(typeof new_date === "string")
{
this._date_helper.set_year(new_date.substring(0, 4));
// Avoid overflow into next month, since we re-use date_helper
this._date_helper.set_date(1);
this._date_helper.set_month(new_date.substring(4, 6));
this._date_helper.set_date(new_date.substring(6, 8));
}
var old_date = this.options.end_date;
this.options.end_date = new Date(this._date_helper.getValue());
let old_date = this.options.end_date;
this.options.end_date = this.date_helper(new_date);
if(old_date !== this.options.end_date && this.isAttached())
{
@ -344,15 +306,74 @@ export class et2_calendar_view extends et2_valueWidget
// None of the above changed anything, hide the loader
if(!this.update_timer)
{
window.setTimeout(jQuery.proxy(function() {this.loader.hide();},this),200);
window.setTimeout(jQuery.proxy(function() {this.loader.hide();}, this), 200);
}
}
get date_helper(): et2_date
/**
* Parse something that we think is a date into an actual date.
*
* The passed value could be a Date, or a string in an unknown format, or a timestamp
*
* @param {Date | string | number} _value
*/
date_helper(_value : Date | string | number)
{
return this._date_helper;
if(_value === null || _value === "" || _value === undefined || _value === 0)
{
return undefined;
}
if(_value instanceof Date)
{
// Return a copy, because often modifications are made after
return new Date(_value.getTime());
}
let date = new Date();
if(typeof _value === "string" && _value.length == 8)
{
// Ymd format: 20000101
date.setFullYear(parseInt(_value.substring(0, 4)));
// Avoid overflow into next month since it already has a value
date.setDate(1);
date.setMonth(parseInt(_value.substring(4, 6)) - 1);
date.setDate(parseInt(_value.substring(6, 8)));
date.setUTCHours(0);
date.setUTCMinutes(0);
date.setUTCSeconds(0);
}
// Check for full timestamp
else 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})|)$/))
{
date = new Date(_value);
}
// timestamp in usertime
else if(typeof _value == 'number' || typeof _value == 'string' && !isNaN(<number><unknown>_value) && _value[0] != '+' && _value[0] != '-')
{
date = new Date((typeof _value == "number" ? _value : parseInt(_value)) * 1000);
}
// @ts-ignore
else if(typeof _value == 'object' && typeof _value.date !== "undefined")
{
// @ts-ignore
return this.date_helper(_value.date);
}
// @ts-ignore
else if(typeof _value == 'object' && typeof _value.valueOf !== "undefined")
{
date = _value;
}
else
{
// string starting with + or - --> add/substract number of seconds from current value
date.setTime(date.getTime() + 1000 * parseInt("" + _value));
}
return date;
}
_createNamespace() {
_createNamespace()
{
return true;
}
@ -369,10 +390,7 @@ export class et2_calendar_view extends et2_valueWidget
var tempDate = new Date();
var now = new Date(tempDate.getFullYear(), tempDate.getMonth(), tempDate.getDate(),tempDate.getHours(),tempDate.getMinutes()-tempDate.getTimezoneOffset(),0);
// Use date widget's existing functions to deal
this._date_helper.set_value(now.toJSON());
now = new Date(this._date_helper.getValue());
now = this.date_helper(now.toJSON());
if(this.get_start_date() <= now && this.get_end_date() >= now)
{
return now;
@ -535,16 +553,13 @@ export class et2_calendar_view extends et2_valueWidget
}
if(!this.drag_create.event)
{
this._date_helper.set_value(this.drag_create.start.date);
var value = jQuery.extend({},
this.drag_create.start,
this.drag_create.end,
{
start: this.drag_create.start.date,
end: this.drag_create.end && this.drag_create.end.date || this.drag_create.start.date,
date: ""+this._date_helper.get_year()+
sprintf("%02d",this._date_helper.get_month())+
sprintf("%02d",this._date_helper.get_date()),
date: "" + formatDate(this.date_helper(this.drag_create.start.date), {dateFormat: "Ymd"}),
title: '',
description: '',
owner: this.options.owner,
@ -687,34 +702,4 @@ export class et2_calendar_view extends et2_valueWidget
* Cache to map owner & resource IDs to names, helps cut down on server requests
*/
static owner_name_cache = {};
public static holiday_cache = {};
/**
* Fetch and cache a list of the year's holidays
*
* @param {et2_calendar_timegrid} widget
* @param {string|numeric} year
* @returns Promise<{[key: string]: Array<object>}>|{[key: string]: Array<object>}
*/
static get_holidays(year) : Promise<{[key: string]: Array<object>}>|{[key: string]: Array<object>}
{
// Loaded in an iframe or something
var view = egw.window.et2_calendar_view ? egw.window.et2_calendar_view : this;
// No country selected causes error, so skip if it's missing
if(!view || !egw.preference('country','common')) return {};
if (typeof view.holiday_cache[year] === 'undefined')
{
// Fetch with json instead of jsonq because there may be more than
// one widget listening for the response by the time it gets back,
// and we can't do that when it's queued.
view.holiday_cache[year] = window.fetch(
egw.link('/calendar/holidays.php', {year: year})
).then((response) => {
return view.holiday_cache[year] = response.json();
});
}
return view.holiday_cache[year];
}
}