/* * Egroupware Calendar event widget * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License * @package etemplate * @subpackage api * @link http://www.egroupware.org * @author Nathan Gray * @version $Id$ */ "use strict"; /*egw:uses /etemplate/js/et2_core_valueWidget; */ /** * Class for a single event, displayed in a timegrid * * * @augments et2_valueWidget */ var et2_calendar_event = et2_valueWidget.extend([et2_IDetachedDOM], { attributes: { "onclick": { "description": "JS code which is executed when the element is clicked. " + "If no handler is provided, or the handler returns true and the event is not read-only, the " + "event will be opened according to calendar settings." } }, /** * Constructor * * @memberOf et2_calendar_daycol */ init: function() { this._super.apply(this, arguments); // Main container this.div = $j(document.createElement("div")) .addClass("calendar_calEvent") .css('width',this.options.width); this.title = $j(document.createElement('div')) .addClass("calendar_calEventHeader") .appendTo(this.div); this.body = $j(document.createElement('div')) .addClass("calendar_calEventBody") .appendTo(this.div); this.icons = $j(document.createElement('div')) .addClass("calendar_calEventIcons") .appendTo(this.title); this.setDOMNode(this.div[0]); }, 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); } }, destroy: function() { this._super.apply(this, arguments); // Unregister, or we'll continue to be notified... var old_app_id = this.options.value.app_id ? this.options.value.app_id : this.options.value.id + (this.options.value.recur_type ? ':'+this.options.value.recur_date : ''); egw.dataUnregisterUID('calendar::'+old_app_id,false,this); }, set_value: function(_value) { // Un-register for updates if(this.options.value) { var old_app_id = this.options.value.app_id ? this.options.value.app_id : this.options.value.id + (this.options.value.recur_type ? ':'+this.options.value.recur_date : ''); egw.dataUnregisterUID('calendar::'+old_app_id,false,this); } this.options.value = _value; // Register for updates var app_id = this.options.value.app_id ? this.options.value.app_id : this.options.value.id + (this.options.value.recur_type ? ':'+this.options.value.recur_date : ''); egw.dataRegisterUID('calendar::'+app_id, function(event) { // Copy to avoid changes, which may cause nm problems event = jQuery.extend({},event); var list = [event]; // Let parent format any missing data this._parent._event_columns(list); // Calculate vertical positioning // TODO: Maybe move this somewhere common between here & parent? var top = 0; var height = 0; if(event.whole_day_on_top) { top = ((this._parent.title.height()/this._parent.div.height())*100) + this._parent.display_settings.rowHeight; height = this._parent.display_settings.rowHeight; } else { top = this._parent._time_to_position(event.start_m,0); height = this._parent._time_to_position(event.end_m,0)-top; } // Position the event - horizontal is controlled by parent this.div.css('top', top+'%'); this.div.css('height', height+'%'); this._update(event); },this,this.getInstanceManager().execId,this.id); if(!egw.dataHasUID('calendar::'+app_id)) { this._update(this.options.value); } }, _update: function(event) { // Copy new information this.options.value = event; var eventId = event.id.match(/-?\d+\.?\d*/g)[0]; var appName = event.id.replace(/-?\d+\.?\d*/g,''); var app_id = event.app_id ? event.app_id : event.id + (event.recur_type ? ':'+event.recur_date : ''); this._parent.date_helper.set_value(event.start); var formatted_start = this._parent.date_helper.getValue(); this.set_id(eventId || event.id); this.div // Empty & re-append to make sure dnd helpers are gone .empty() .append(this.title) .append(this.body) // ? .attr('data-draggable-id',event['id']+'_O'+event.owner+'_C'+(event.owner<0?'group'+Math.abs(event.owner):event.owner)) // Put everything we need for basic interaction here, so it's available immediately .attr('data-id', eventId || event.id) .attr('data-app', appName || 'calendar') .attr('data-app_id', app_id) .attr('data-start', formatted_start) .attr('data-owner', event.owner) .attr('data-recur_type', event.recur_type) .attr('data-resize', event.whole_day ? 'WD' : '' + (event.recur_type ? 'S':'')) .addClass(event.class) .toggleClass('calendar_calEventPrivate', event.private) // Remove any category classes .removeClass(function(index, css) { return (css.match (/(^|\s)cat_\S+/g) || []).join(' '); }) // Remove any resize classes, the handles are gone due to empty() .removeClass('ui-resizable'); if(event.category) { this.div.addClass('cat_' + event.category); } this.div.css('border-color', this.div.css('background-color')); this.div.toggleClass('calendar_calEventUnknown', event.participants[egw.user('account_id')] ? event.participants[egw.user('account_id')][0] == 'U' : false); this.title.toggle(!event.whole_day_on_top); this.body.toggleClass('calendar_calEventBodySmall', event.whole_day_on_top || false); // Header var title = !event.is_private ? event['title'] : egw.lang('private'); var small_height = event['end_m']-event['start_m'] < 2*this._parent.display_settings.granularity || event['end_m'] <= this._parent.display_settings.wd_start || event['start_m'] >= this._parent.display_settings.wd_end; this.div.attr('data-title', title); this.title.text(small_height ? title : this._get_timespan(event)) // Set title color based on background brightness .css('color', jQuery.Color(this.div.css('background-color')).lightness() > 0.5 ? 'black':'white'); this.icons.appendTo(this.title) .html(this._icons()); // Body if(event.whole_day_on_top) { this.body.html(title); } else { this.body.html(''+title+'') } this.body // Set background color to a lighter version of the header color .css('background-color',jQuery.Color(this.div.css('background-color')).lightness("+=0.3")); this.set_statustext(this._tooltip()); }, _tooltip: function() { var status_class = 'calendar_calEventAllAccepted'; status: for(var id in this.options.value.participants) { var status = this.options.value.participants[id]; if (parseInt(id) < 0) continue; // as we cant accept/reject groups, we dont care about them here status = et2_calendar_event.split_status(status); switch (status) { case 'A': case '': // app without status break; case 'U': status_class = 'calendar_calEventSomeUnknown'; break status; // break for default: status_class = 'calendar_calEventAllAnswered'; break; } } var border = this.div.css('border-color'); var bg_color = this.div.css('background-color'); var header_color = this.title.css('color'); this._parent.date_helper.set_value(this.options.value.start); var start = this._parent.date_helper.input_date.val(); this._parent.date_helper.set_value(this.options.value.end); var end = this._parent.date_helper.input_date.val(); var times = !this.options.value.multiday ? ''+this.egw().lang('Time')+':' + this._get_timespan(this.options.value) : ''+this.egw().lang('Start') + ':' +start+ ''+this.egw().lang('End') + ':' + end var cat = et2_createWidget('select-cat',{'readonly':true},this); cat.set_value(this.options.value.category); var cat_label = cat.node.innerText; cat.destroy(); return '
'+
''+this.div.attr('data-title')+'
'+
this.options.value.description+'
'+times+'
'+ (this.options.value.location ? ''+this.egw().lang('Location') + ':' + this.options.value.location+'
' : '')+ (cat_label ? ''+this.egw().lang('Category') + ':' + cat_label+'
' : '')+ ''+this.egw().lang('Participants')+':
'+
(this.options.value.parts ? this.options.value.parts.replace("\n","
"):'')+'