Some code cleanup

This commit is contained in:
Nathan Gray 2016-01-13 22:07:09 +00:00
parent 1e2b03abb0
commit 70686f0847
6 changed files with 330 additions and 205 deletions

View File

@ -3040,7 +3040,7 @@ app.classes.calendar = AppJS.extend(
{
var tempDate = new Date();
var today = new Date(tempDate.getFullYear(), tempDate.getUTCMonth(), tempDate.getUTCDate());
var holidays = et2_calendar_daycol.get_holidays({day_class_holiday: function() {}}, date.getFullYear());
var holidays = et2_calendar_view.get_holidays({day_class_holiday: function() {}}, date.getFullYear());
var day_holidays = holidays[''+date.getFullYear() +
sprintf("%02d",date.getMonth()+1) +
sprintf("%02d",date.getDate())];

View File

@ -17,11 +17,11 @@
*/
/**
* Class which implements the "calendar-timegrid" XET-Tag for displaying a span of days
* Class which implements the "calendar-timegrid" XET-Tag for displaying a single days
*
* This widget is responsible for the times on the side
* This widget is responsible mostly for positioning its events
*
* @augments et2_DOMWidget
* @augments et2_valueWidget
*/
var et2_calendar_daycol = et2_valueWidget.extend([et2_IDetachedDOM, et2_IResizeable],
{
@ -35,7 +35,7 @@ var et2_calendar_daycol = et2_valueWidget.extend([et2_IDetachedDOM, et2_IResizea
},
owner: {
name: "Owner",
type: "any", // Integer, or array of integers
type: "any", // Integer, string, or array of either
default: 0,
description: "Account ID number of the calendar owner, if not the current user"
},
@ -83,7 +83,7 @@ var et2_calendar_daycol = et2_valueWidget.extend([et2_IDetachedDOM, et2_IResizea
this.date_helper = et2_createWidget('date-time',{},null);
this.date_helper.loadingFinished();
// Init to defaults, just in case
// Init to defaults, just in case - they will be updated from parent
this.display_settings = {
wd_start: 60*9,
wd_end: 60*17,
@ -128,7 +128,7 @@ var et2_calendar_daycol = et2_valueWidget.extend([et2_IDetachedDOM, et2_IResizea
},
/**
* Draw the individual divs for clicking
* Draw the individual divs for clicking to add an event
*/
_draw: function() {
// Remove any existing
@ -197,7 +197,7 @@ var et2_calendar_daycol = et2_valueWidget.extend([et2_IDetachedDOM, et2_IResizea
* Set the date
*
* @param {string|Date} _date New date
* @param {Object[]} events=false List of events to be displayed, or false to
* @param {Object[]} events=false List of event data to be displayed, or false to
* automatically fetch data from content array
* @param {boolean} force_redraw=false Redraw even if the date is the same.
* Used for when new data is available.
@ -295,7 +295,10 @@ var et2_calendar_daycol = et2_valueWidget.extend([et2_IDetachedDOM, et2_IResizea
/**
* Set the owner of this day
*
* @param {number|number[]} _owner Account ID
* @param {number|number[]|string|string[]} _owner - Owner ID, which can
* be an account ID, a resource ID (as defined in calendar_bo, not
* necessarily an entry from the resource app), or a list containing a
* combination of both.
*/
set_owner: function(_owner) {
@ -330,6 +333,9 @@ var et2_calendar_daycol = et2_valueWidget.extend([et2_IDetachedDOM, et2_IResizea
/**
* Callback used when the daywise data changes
*
* Events should update themselves when their data changes, here we are
* dealing with a change in which events are displayed on this day.
*
* @param {String[]} event_ids
* @returns {undefined}
@ -406,7 +412,7 @@ var et2_calendar_daycol = et2_valueWidget.extend([et2_IDetachedDOM, et2_IResizea
);
// Holidays and birthdays
var holidays = et2_calendar_daycol.get_holidays(this,this.options.date.substring(0,4));
var holidays = et2_calendar_view.get_holidays(this,this.options.date.substring(0,4));
var holiday_list = [];
if(holidays && holidays[this.options.date])
{
@ -457,8 +463,8 @@ var et2_calendar_daycol = et2_valueWidget.extend([et2_IDetachedDOM, et2_IResizea
{
var node = this._children[this._children.length-1];
this.removeChild(node);
node.free();
}
node.free();
}
// Make sure children are in cronological order, or columns are backwards
events.sort(function(a,b) {
@ -547,7 +553,7 @@ var et2_calendar_daycol = et2_valueWidget.extend([et2_IDetachedDOM, et2_IResizea
event.title.css('top',timegrid.scrolling.scrollTop() - event.div.position().top);
event.body.css('padding-top',timegrid.scrolling.scrollTop() - event.div.position().top);
}
// Too many in list view, show indicator
// Too many in gridlist view, show indicator
else if (this.display_settings.granularity === 0 && hidden.completely)
{
var day = this;
@ -728,10 +734,11 @@ var et2_calendar_daycol = et2_valueWidget.extend([et2_IDetachedDOM, et2_IResizea
},
/**
* Position the event according to it's time and how this widget is laid
* Position the event according to its time and how this widget is laid
* out.
*
* @param {undefined|Object|et2_calendar_event} event
* @param {et2_calendar_event} [event] - Event to be updated
* If a single event is not provided, all events are repositioned.
*/
position_event: function(event)
{
@ -750,8 +757,6 @@ var et2_calendar_daycol = et2_valueWidget.extend([et2_IDetachedDOM, et2_IResizea
}
if (left + width > 100.0) width = 98.0 - left;
var whole_day_counter = 0;
for(var i = 0; (columns[c].indexOf(event) >= 0 || !event) && i < columns[c].length; i++)
{
// Calculate vertical positioning
@ -794,8 +799,8 @@ var et2_calendar_daycol = et2_valueWidget.extend([et2_IDetachedDOM, et2_IResizea
columns[c][i].div.appendTo(this.div);
this._parent.resizeTimes();
}
top = this._time_to_position(columns[c][i].options.value.start_m,whole_day_counter);
height = this._time_to_position(columns[c][i].options.value.end_m,whole_day_counter)-top;
top = this._time_to_position(columns[c][i].options.value.start_m);
height = this._time_to_position(columns[c][i].options.value.end_m)-top;
}
// Position the event
@ -831,21 +836,16 @@ var et2_calendar_daycol = et2_valueWidget.extend([et2_IDetachedDOM, et2_IResizea
* This calculation is a percentage from 00:00 to 23:59
*
* @param {int} time in minutes from midnight
* @param {int} [row_offset=0] Add extra spacing for additional rows
* @return {float} position in percent
*/
_time_to_position: function(time,row_offset)
_time_to_position: function(time)
{
var pos = 0.0;
if(typeof row_offset === 'undefined')
{
row_offset = 0;
}
// 24h
pos = ((time / 60) / 24) * 100
pos = ((time / 60) / 24) * 100;
pos = pos.toFixed(1)
pos = pos.toFixed(1);
return pos;
},
@ -957,54 +957,3 @@ var et2_calendar_daycol = et2_valueWidget.extend([et2_IDetachedDOM, et2_IResizea
});
et2_register_widget(et2_calendar_daycol, ["calendar-daycol"]);
// Static class stuff
jQuery.extend(et2_calendar_daycol,
{
holiday_cache: {},
/**
* Fetch and cache a list of the year's holidays
*
* @param {et2_calendar_timegrid} widget
* @param {string|numeric} year
* @returns {Array}
*/
get_holidays: function(widget,year)
{
// Loaded in an iframe or something
if(!egw.window.et2_calendar_daycol) return {};
var cache = egw.window.et2_calendar_daycol.holiday_cache[year];
if (typeof cache == '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.
egw.window.et2_calendar_daycol.holiday_cache[year] = egw.json(
'calendar_timegrid_etemplate_widget::ajax_get_holidays',
[year]
).sendRequest(true);
}
cache = egw.window.et2_calendar_daycol.holiday_cache[year];
if(typeof cache.done == 'function')
{
// pending, wait for it
cache.done(jQuery.proxy(function(response) {
egw.window.et2_calendar_daycol.holiday_cache[this.year] = response.response[0].data||undefined;
egw.window.setTimeout(jQuery.proxy(function() {
// Make sure widget hasn't been destroyed while we wait
if(typeof this.widget.free == 'undefined')
{
this.widget.day_class_holiday();
}
},this),1);
},{widget:widget,year:year}));
return {};
}
else
{
return cache;
}
}
});

View File

@ -16,7 +16,28 @@
*/
/**
* Class for a single event, displayed in a timegrid
* Class for a single event, displayed in either the timegrid or planner view
*
* It is possible to directly provide all information directly, but calendar
* uses egw.data for caching, so ID is all that is needed.
*
* Note that there are several pieces of information that have 'ID' in them:
* - row_id - used by both et2_calendar_event and the nextmatch to uniquely
* identify a particular entry or entry ocurrence
* - id - Recurring events may have their recurrence as a timestamp after their ID,
* such as '194:1453318200', or not. It's usually (always?) the same as row ID.
* - app_id - the ID according to the source application. For calendar, this
* is the same as ID (but always with the recurrence), for other apps this is
* usually just an integer. With app_id and app, you should be able to call
* egw.open() and get the specific entry.
* - Events from other apps will have their app name prepended to their ID, such
* as 'infolog123', so app_id and id will be different for these events
* - Cache ID is the same as other apps, and looks like 'calendar::<row_id>'
* - The DOM ID for the containing div is event_<row_id>
*
* Events are expected to be added to either et2_calendar_daycol or
* et2_calendar_planner_row rather than either et2_calendar_timegrid or
* et2_calendar_planner directly.
*
*
* @augments et2_valueWidget
@ -88,20 +109,12 @@ var et2_calendar_event = et2_valueWidget.extend([et2_IDetachedDOM],
doLoadingFinished: function() {
this._super.apply(this, arguments);
// Parent will have everything we need, just load it from there
if(this.title.text() == '' && this.options.date &&
this._parent && this._parent.instanceOf(et2_calendar_timegrid))
{
// Forces an update
var date = this.options.date;
this.options.date = '';
this.set_date(date);
}
// Already know what is needed to hook to cache
if(this.options.value && this.options.value.row_id)
{
egw.dataRegisterUID(
'calendar::'+this.options.value.row_id,
this._UID_callback ,
this._UID_callback,
this,
this.getInstanceManager().execId,
this.id
@ -132,7 +145,7 @@ var et2_calendar_event = et2_valueWidget.extend([et2_IDetachedDOM],
// Unregister, or we'll continue to be notified...
if(this.options.value)
{
var old_app_id = this.options.value.app_id;
var old_app_id = this.options.value.row_id;
egw.dataUnregisterUID('calendar::'+old_app_id,false,this);
}
},
@ -160,9 +173,12 @@ var et2_calendar_event = et2_valueWidget.extend([et2_IDetachedDOM],
egw.dataStoreUID('calendar::'+id, _value);
}
},
/**
* Callback for changes in cached data
*/
_UID_callback: function _UID_callback(event) {
// Make sure id is a string
// Make sure id is a string, check values
if(event)
{
this._values_check(event);
@ -201,6 +217,9 @@ var et2_calendar_event = et2_valueWidget.extend([et2_IDetachedDOM],
}
},
/**
* Draw the event
*/
_update: function(event) {
// Copy new information
@ -329,6 +348,7 @@ var et2_calendar_event = et2_valueWidget.extend([et2_IDetachedDOM],
Math.max(0.8, parseFloat(jQuery.Color(this.title.css('background-color')).lightness()))
));
// Tooltip
this.set_statustext(this._tooltip());
},
@ -361,6 +381,11 @@ var et2_calendar_event = et2_valueWidget.extend([et2_IDetachedDOM],
return status_class;
},
/**
* Create tooltip shown on hover
*
* @return {String}
*/
_tooltip: function() {
if(!this.div) return '';
@ -588,6 +613,22 @@ var et2_calendar_event = et2_valueWidget.extend([et2_IDetachedDOM],
event.whole_day_on_top = (event.non_blocking && event.non_blocking != '0');
}
},
/**
* Check to see if the provided event information is for the same date as
* what we're currently expecting, and that it has not been changed.
*
* If the date has changed, we adjust the associated daywise caches to move
* the event's ID to where it should be.
*
* @param {Object} event Map of event data from cache
* @param {string} event.date For non-recurring, single day events, this is
* the date the event is on.
* @param {string} event.start Start of the event (used for multi-day events)
* @param {string} event.end End of the event (used for multi-day events)
*
* @return {Boolean} Provided event data is for the same date
*/
_sameday_check: function(event)
{
// Event somehow got orphaned, or deleted
@ -672,7 +713,9 @@ var et2_calendar_event = et2_valueWidget.extend([et2_IDetachedDOM],
/**
* Show the recur prompt for this event
*
* @param {function} callback
* Calls et2_calendar_event.recur_prompt with this event's value.
*
* @param {et2_calendar_event~prompt_callback} callback
* @param {Object} [extra_data]
*/
recur_prompt: function(callback, extra_data)
@ -683,7 +726,9 @@ var et2_calendar_event = et2_valueWidget.extend([et2_IDetachedDOM],
/**
* Show the series split prompt for this event
*
* @param {function} callback
* Calls et2_calendar_event.series_split_prompt with this event's value.
*
* @param {et2_calendar_event~prompt_callback} callback
*/
series_split_prompt: function(callback)
{
@ -750,17 +795,33 @@ var et2_calendar_event = et2_valueWidget.extend([et2_IDetachedDOM],
et2_register_widget(et2_calendar_event, ["calendar-event"]);
// Static class stuff
/**
* @callback et2_calendar_event~prompt_callback
* @param {string} button_id - One of ok, exception, series, single or cancel
* depending on which buttons are on the prompt
* @param {Object} event_data - Event information - whatever you passed in to
* the prompt.
*/
/**
* Recur prompt
* If the event is recurring, asks the user if they want to edit the event as
* an exception, or change the whole series. Then the callback is called.
*
* If callback is not provided, egw.open() will be used to open an edit dialog.
*
* If you call this on a single (non-recurring) event, the callback will be
* executed immediately, with the passed button_id as 'single'.
*
* @param {Object} event_data - Event information
* @param {string} event_data.id - Unique ID for the event, possibly with a timestamp
* @param {string} event_data.id - Unique ID for the event, possibly with a
* timestamp
* @param {string|Date} event_data.start - Start date/time for the event
* @param {number} event_data.recur_type - Recur type, or 0 for a non-recurring event
* @param {Function} [callback] - Callback is called with the button (exception, series, single or cancel) and the event data.
* @param {Object} [extra_data] - Additional data passed to the callback, used as extra parameters for default callback
* @param {et2_calendar_event~prompt_callback} [callback] - Callback is
* called with the button (exception, series, single or cancel) and the event
* data.
* @param {Object} [extra_data] - Additional data passed to the callback, used
* as extra parameters for default callback
*
* @augments {et2_calendar_event}
*/
@ -820,11 +881,14 @@ et2_calendar_event.recur_prompt = function(event_data, callback, extra_data)
* to split the series, ending the current one and creating a new one with the changes.
* This prompts the user if they really want to do that.
*
* There is no default callback, and nothing happens if you call this on a
* single (non-recurring) event
*
* @param {Object} event_data - Event information
* @param {string} event_data.id - Unique ID for the event, possibly with a timestamp
* @param {string|Date} instance_date - The date of the edited instance of the event
* @param {Function} [callback] - Callback is called with the button (ok or cancel) and the event data.
*
* @param {et2_calendar_event~prompt_callback} callback - Callback is
* called with the button (ok or cancel) and the event data.
* @augments {et2_calendar_event}
*/
et2_calendar_event.series_split_prompt = function(event_data, instance_date, callback)
@ -889,7 +953,7 @@ et2_calendar_event.split_status = function(status,quantity,role)
/**
* The egw_action system requires an egwActionObjectInterface Interface implementation
* to tie actions to DOM nodes. This one can be used by any widget.
* to tie actions to DOM nodes. I'm not sure if we need this.
*
* The class extension is different than the widgets
*

View File

@ -19,10 +19,11 @@
/**
* Class which implements the "calendar-planner" XET-Tag for displaying a longer
* ( > 10 days) span of time
* ( > 10 days) span of time. Events can be grouped into rows by either user,
* category, or month. Their horizontal position and size in the row is determined
* by their start date and duration relative to the displayed date range.
*
* @augments et2_valueWidget
* @class
* @augments et2_calendar_view
*/
var et2_calendar_planner = et2_calendar_view.extend([et2_IDetachedDOM, et2_IResizeable],
{
@ -109,12 +110,6 @@ var et2_calendar_planner = et2_calendar_view.extend([et2_IDetachedDOM, et2_IResi
{
egw.dataUnregisterUID(this.registeredCallbacks[i],false,this);
}
// Stop the invalidate timer
if(this.update_timer)
{
window.clearTimeout(this.update_timer);
}
},
doLoadingFinished: function() {
@ -1114,7 +1109,7 @@ var et2_calendar_planner = et2_calendar_view.extend([et2_IDetachedDOM, et2_IResi
var day_class = '';
// Holidays and birthdays
var holidays = et2_calendar_daycol.get_holidays(this,date.getUTCFullYear());
var holidays = et2_calendar_view.get_holidays(this,date.getUTCFullYear());
// Pass a string rather than the date object, to make sure it doesn't get changed
this.date_helper.set_value(date.toJSON());
@ -1434,7 +1429,7 @@ var et2_calendar_planner = et2_calendar_view.extend([et2_IDetachedDOM, et2_IResi
var drop_date = this.dropEnd.toJSON() ||false;
var event_data = planner._get_event_info(ui.draggable);
var event_widget = planner.getWidgetById('event_'+event_data.id);
var event_widget = planner.getWidgetById(event_data.widget_id);
if(event_widget)
{
event_widget._parent.date_helper.set_value(drop_date);
@ -1582,21 +1577,7 @@ var et2_calendar_planner = et2_calendar_view.extend([et2_IDetachedDOM, et2_IResi
{
if(typeof events !== 'object') return false;
if(events.owner)
{
this.set_owner(events.owner);
delete events.owner;
}
if(events.start_date)
{
this.set_start_date(events.start_date);
delete events.start_date;
}
if(events.end_date)
{
this.set_end_date(events.end_date);
delete events.end_date;
}
this._super.apply(this, arguments);
if(typeof events.length === "undefined" && events)
{
@ -1719,7 +1700,7 @@ var et2_calendar_planner = et2_calendar_view.extend([et2_IDetachedDOM, et2_IResi
* onclick function.
*
* @param {Event} _ev
* @returns {boolean}
* @returns {boolean} Continue processing event (true) or stop (false)
*/
click: function(_ev)
{
@ -1793,29 +1774,14 @@ var et2_calendar_planner = et2_calendar_view.extend([et2_IDetachedDOM, et2_IResi
return false;
}
},
_get_event_info: function(dom_node)
{
// Determine as much relevant info as can be found
var event_node = $j(dom_node).closest('[data-id]',this.div)[0];
var day_node = $j(event_node).closest('[data-date]',this.div)[0];
return jQuery.extend({
event_node: event_node,
day_node: day_node,
},
event_node ? event_node.dataset : {},
day_node ? day_node.dataset : {}
);
},
/**
* Get time from position
*
* @param {number} x
* @param {number} y
* @returns {DOMNode[]} time node(s) for the given position
* @returns {Date|Boolean} A time for the given position, or false if one
* could not be determined.
*/
_get_time_from_position: function(x,y) {

View File

@ -20,9 +20,16 @@
/**
* Class which implements the "calendar-timegrid" XET-Tag for displaying a span of days
*
* This widget is responsible for the times on the side
* This widget is responsible for the times on the side, and it is also the
* controller for both positioning and setting the day columns. Day columns are
* recycled rather than removed and re-created to reduce reloading. Similarly,
* the horizontal time grid (when used - see granularity attribute) is only
* redrawn or resized when needed. Unfortunately resizing is needed every time
* the all day section has an event added or removed so the full work day from
* start time to end time is properly displayed.
*
* @augments et2_DOMWidget
*
* @augments et2_calendar_view
*/
var et2_calendar_timegrid = et2_calendar_view.extend([et2_IDetachedDOM, et2_IResizeable],
{
@ -126,12 +133,6 @@ var et2_calendar_timegrid = et2_calendar_view.extend([et2_IDetachedDOM, et2_IRes
},
destroy: function() {
// Stop the invalidate timer
if(this.update_timer)
{
window.clearTimeout(this.update_timer);
}
// Stop listening to tab changes
$j(framework.getApplicationByName('calendar').tab.contentDiv).off('show.' + this.id);
@ -151,11 +152,7 @@ var et2_calendar_timegrid = et2_calendar_view.extend([et2_IDetachedDOM, et2_IRes
this.scrolling = null;
this._labelContainer = null;
// Stop the invalidate timer
if(this.update_timer)
{
window.clearTimeout(this.update_timer);
}
// Stop the resize timer
if(this.resize_timer)
{
window.clearTimeout(this.resize_timer);
@ -386,11 +383,11 @@ var et2_calendar_timegrid = et2_calendar_view.extend([et2_IDetachedDOM, et2_IRes
var drop_date = dropEnd.date||false;
var event_data = timegrid._get_event_info(ui.draggable);
var event_widget = timegrid.getWidgetById('event_'+event_data.id);
var event_widget = timegrid.getWidgetById(event_data.widget_id);
if(!event_widget)
{
// Widget was moved across weeks / owners
event_widget = timegrid.getParent().getWidgetById('event_'+event_data.id);
event_widget = timegrid.getParent().getWidgetById(event_data.widget_id);
}
if(event_widget)
{
@ -611,7 +608,7 @@ var et2_calendar_timegrid = et2_calendar_view.extend([et2_IDetachedDOM, et2_IRes
/**
* Creates the DOM nodes for the times in the left column, and the horizontal
* lines (mostly via CSS) that span the whole time span.
* lines (mostly via CSS) that span the whole date range.
*/
_drawTimes: function() {
$j('.calendar_calTimeRow',this.div).remove();
@ -726,7 +723,8 @@ var et2_calendar_timegrid = et2_calendar_view.extend([et2_IDetachedDOM, et2_IRes
/**
* As window size and number of all day non-blocking events change, we need
* to re-scale the time grid to make sure the full working day is shown.
*
*
* We use a timeout to avoid doing it multiple times if redrawing or resizing.
*/
resizeTimes: function() {
// Wait a bit to see if anything else changes, then re-draw the times
@ -746,7 +744,11 @@ var et2_calendar_timegrid = et2_calendar_view.extend([et2_IDetachedDOM, et2_IRes
}
},this),1);
},
/**
* Re-scale the time grid to make sure the full working day is shown.
* This is the timeout callback that does the actual re-size immediately.
*/
_resizeTimes: function() {
if(!this.div.is(':visible'))
@ -876,6 +878,7 @@ var et2_calendar_timegrid = et2_calendar_view.extend([et2_IDetachedDOM, et2_IRes
day.set_left((day_width * i) + 'px');
if(daily_owner)
{
// Each 'day' is the same date, different user
day.set_id(this.day_list[0]+'-'+this.options.owner[i]);
day.set_date(this.day_list[0], false);
day.set_owner(this.options.owner[i]);
@ -883,7 +886,7 @@ var et2_calendar_timegrid = et2_calendar_view.extend([et2_IDetachedDOM, et2_IRes
}
else
{
// Go back to self-calculated date
// Go back to self-calculated date by clearing the label
day.set_label('');
day.set_id(this.day_list[i]);
day.set_date(this.day_list[i], this.value[this.day_list[i]] || false);
@ -1258,50 +1261,41 @@ var et2_calendar_timegrid = et2_calendar_view.extend([et2_IDetachedDOM, et2_IRes
/**
* Provide specific data to be displayed.
* This is a way to set start and end dates, owner and event data in once call.
* This is a way to set start and end dates, owner and event data in one call.
*
* Events will be retrieved automatically from the egw.data cache, so there
* is no great need to provide them.
*
* @param {Object[]} events Array of events, indexed by date in Ymd format:
* {
* 20150501: [...],
* 20150502: [...]
* }
* Days should be in order.
*
* @param {string|number|Date} events.start_date - New start date
* @param {string|number|Date} events.end_date - New end date
* @param {number|number[]|string|string[]} event.owner - Owner ID, which can
* be an account ID, a resource ID (as defined in calendar_bo, not
* necessarily an entry from the resource app), or a list containing a
* combination of both.
*/
set_value: function(events)
{
if(typeof events !== 'object') return false;
this.loader.show();
var use_days_sent = true;
if(events.id)
{
this.set_id(events.id);
delete events.id;
}
if(events.start_date)
{
this.set_start_date(events.start_date);
delete events.start_date;
use_days_sent = false;
}
if(events.end_date)
{
this.set_end_date(events.end_date);
delete events.end_date;
use_days_sent = false;
}
// set_owner() wants start_date set to get the correct week number
// for the corner label
if(events.owner)
{
this.set_owner(events.owner);
delete events.owner;
}
this.value = events || {};
this._super.apply(this,arguments);
if(use_days_sent)
{
var day_list = Object.keys(events);
@ -1400,6 +1394,10 @@ var et2_calendar_timegrid = et2_calendar_view.extend([et2_IDetachedDOM, et2_IRes
/**
* Set how big the time divisions are
*
* Setting granularity to 0 will remove the time divisions and display
* each days events in a list style. This 'gridlist' is not to be confused
* with the list view, which uses a nextmatch.
*
* @param {number} minutes
*/
@ -1514,7 +1512,7 @@ var et2_calendar_timegrid = et2_calendar_view.extend([et2_IDetachedDOM, et2_IRes
* onclick function.
*
* @param {Event} _ev
* @returns {boolean}
* @returns {boolean} Continue processing event (true) or stop (false)
*/
click: function(_ev)
{
@ -1577,23 +1575,11 @@ var et2_calendar_timegrid = et2_calendar_view.extend([et2_IDetachedDOM, et2_IRes
}
},
_get_event_info: function(dom_node)
{
// Determine as much relevant info as can be found
var event_node = $j(dom_node).closest('[data-id]',this.div)[0];
var day_node = $j(event_node).closest('[data-date]',this.div)[0];
return jQuery.extend({
event_node: event_node,
day_node: day_node,
},
event_node ? event_node.dataset : {},
day_node ? day_node.dataset : {}
);
},
/**
* Get time from position
* Get time from position for drag and drop
*
* This does not return an actual time on a clock, but finds the closest
* time node (.calendar_calAddEvent or day column) to the given position.
*
* @param {number} x
* @param {number} y

View File

@ -17,6 +17,10 @@
/**
* Parent class for the various calendar views to reduce copied code
*
*
* et2_calendar_view is responsible for its own loader div, which is displayed while
* the times & days are redrawn.
*
* @augments et2_valueWidget
*/
var et2_calendar_view = et2_valueWidget.extend(
@ -54,6 +58,7 @@ var et2_calendar_view = et2_valueWidget.extend(
this.date_helper.loadingFinished();
this.loader = $j('<div class="egw-loading-prompt-container ui-front loading"></div>');
this.update_timer = null;
},
destroy: function destroy() {
@ -62,6 +67,12 @@ var et2_calendar_view = et2_valueWidget.extend(
// 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)
{
window.clearTimeout(this.update_timer);
}
},
doLoadingFinished: function() {
@ -80,7 +91,9 @@ var et2_calendar_view = et2_valueWidget.extend(
*
* @memberOf et2_calendar_view
*/
invalidate: function invalidate(trigger_event) {},
invalidate: function invalidate(trigger_event) {
// If this wasn't a stub, we'd set this.update_timer
},
/**
* Returns the current start date
@ -107,7 +120,11 @@ var et2_calendar_view = et2_valueWidget.extend(
/**
* Change the start date
*
* @param {string|number|Date} new_date New starting date
* Changing the start date will invalidate the display, and it will be redrawn
* after a timeout.
*
* @param {string|number|Date} new_date New starting date. Strings can be in
* any format understood by et2_widget_date, or Ymd (eg: 20160101).
* @returns {undefined}
*
* @memberOf et2_calendar_view
@ -143,7 +160,11 @@ var et2_calendar_view = et2_valueWidget.extend(
/**
* Change the end date
*
* @param {string|number|Date} new_date New end date
* Changing the end date will invalidate the display, and it will be redrawn
* after a timeout.
*
* @param {string|number|Date} new_date - New end date. Strings can be in
* any format understood by et2_widget_date, or Ymd (eg: 20160101).
* @returns {undefined}
*
* @memberOf et2_calendar_view
@ -178,7 +199,13 @@ var et2_calendar_view = et2_valueWidget.extend(
/**
* Set which users to display
*
* @param {number|number[]|string|string[]} _owner Account ID
* Changing the owner will invalidate the display, and it will be redrawn
* after a timeout.
*
* @param {number|number[]|string|string[]} _owner - Owner ID, which can
* be an account ID, a resource ID (as defined in calendar_bo, not
* necessarily an entry from the resource app), or a list containing a
* combination of both.
*
* @memberOf et2_calendar_view
*/
@ -207,6 +234,60 @@ var et2_calendar_view = et2_valueWidget.extend(
}
},
/**
* Provide specific data to be displayed.
* This is a way to set start and end dates, owner and event data in one call.
*
* If events are not provided in the array,
* @param {Object[]} events Array of events, indexed by date in Ymd format:
* {
* 20150501: [...],
* 20150502: [...]
* }
* Days should be in order.
* @param {string|number|Date} events.start_date - New start date
* @param {string|number|Date} events.end_date - New end date
* @param {number|number[]|string|string[]} event.owner - Owner ID, which can
* be an account ID, a resource ID (as defined in calendar_bo, not
* necessarily an entry from the resource app), or a list containing a
* combination of both.
*/
set_value: function set_value(events)
{
if(typeof events !== 'object') return false;
if(events.id)
{
this.set_id(events.id);
delete events.id;
}
if(events.start_date)
{
this.set_start_date(events.start_date);
delete events.start_date;
}
if(events.end_date)
{
this.set_end_date(events.end_date);
delete events.end_date;
}
// set_owner() wants start_date set to get the correct week number
// for the corner label
if(events.owner)
{
this.set_owner(events.owner);
delete events.owner;
}
this.value = events || {};
// None of the above changed anything, hide the loader
if(!this.update_timer)
{
window.setTimeout(jQuery.proxy(function() {this.loader.hide();},this),100);
}
},
/**
* Calendar supports many different owner types, including users & resources.
* This translates an ID to a user-friendly name.
@ -252,5 +333,84 @@ var et2_calendar_view = et2_valueWidget.extend(
}
}
return user;
},
/**
* Find the event information linked to a given DOM node
*
* @param {HTMLElement} dom_node - It should have something to do with an event
* @returns {Object}
*/
_get_event_info: function _get_event_info(dom_node)
{
// Determine as much relevant info as can be found
var event_node = $j(dom_node).closest('[data-id]',this.div)[0];
var day_node = $j(event_node).closest('[data-date]',this.div)[0];
// Widget ID should be the DOM node ID without the event_ prefix
var widget_id = event_node.id || '';
widget_id = widget_id.split('event_');
widget_id.shift();
return jQuery.extend({
event_node: event_node,
day_node: day_node,
widget_id: 'event_' + widget_id.join('')
},
event_node ? event_node.dataset : {},
day_node ? day_node.dataset : {}
);
},
});
// Static class stuff
jQuery.extend(et2_calendar_view,
{
holiday_cache: {},
/**
* Fetch and cache a list of the year's holidays
*
* @param {et2_calendar_timegrid} widget
* @param {string|numeric} year
* @returns {Array}
*/
get_holidays: function(widget,year)
{
// Loaded in an iframe or something
if(!egw.window.et2_calendar_view) return {};
var cache = egw.window.et2_calendar_view.holiday_cache[year];
if (typeof cache == '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.
egw.window.et2_calendar_view.holiday_cache[year] = egw.json(
'calendar_timegrid_etemplate_widget::ajax_get_holidays',
[year]
).sendRequest(true);
}
cache = egw.window.et2_calendar_view.holiday_cache[year];
if(typeof cache.done == 'function')
{
// pending, wait for it
cache.done(jQuery.proxy(function(response) {
egw.window.et2_calendar_view.holiday_cache[this.year] = response.response[0].data||undefined;
egw.window.setTimeout(jQuery.proxy(function() {
// Make sure widget hasn't been destroyed while we wait
if(typeof this.widget.free == 'undefined')
{
this.widget.day_class_holiday();
}
},this),1);
},{widget:widget,year:year}));
return {};
}
else
{
return cache;
}
}
});