/* * 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: { "value": { type: "any", default: et2_no_init }, "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") .addClass(this.options.class) .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... 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); } }, 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) { // Check for changing days in the grid view if(this._parent && this._parent.instanceOf(et2_calendar_daycol) && this.options.value.date && event.date != this.options.value.date) { // Date changed, reparent var new_parent = this._parent._parent.getWidgetById(event.date); if(new_parent) { new_parent.addChild(this); } else { // Could not find the right date this._parent.removeChild(this); this.destroy(); return; } } // Copy to avoid changes, which may cause nm problems this.options.value = jQuery.extend({},event); // Let parent position this._parent.position_event(this); // Parent may remove this if the date isn't the same if(this._parent) { this._update(this.options.value); } },this,this.getInstanceManager().execId,this.id); if(_value && !egw.dataHasUID('calendar::'+app_id)) { egw.dataStoreUID('calendar::'+app_id, _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.valueOf ? new Date(event.start) : event.start); var formatted_start = this._parent.date_helper.getValue(); this.set_id('event_' + (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':'')) // Remove any category classes .removeClass(function(index, css) { return (css.match (/(^|\s)cat_\S+/g) || []).join(' '); }) // Remove any status classes .removeClass(function(index, css) { return (css.match(/calendar_calEvent\S+/g) || []).join(' '); }) // Remove any resize classes, the handles are gone due to empty() .removeClass('ui-resizable') .addClass(event.class) .toggleClass('calendar_calEventPrivate', event.private); this.options.class = event.class; 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.div.addClass(this._status_class()); 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 = true; if(this._parent.display_settings) { 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('background-color', this.div.css('background-color')) .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.title.css('background-color')).lightness("+=0.3")); this.set_statustext(this._tooltip()); }, /** * Examines the participants & returns CSS classname for status * * @returns {String} */ _status_class: function() { var status_class = 'calendar_calEventAllAccepted'; 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'; return status_class; // break for default: status_class = 'calendar_calEventAllAnswered'; break; } } return status_class; }, _tooltip: function() { 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.valueOf ? new Date(this.options.value.start) : this.options.value.start); var start = this._parent.date_helper.input_date.val(); this._parent.date_helper.set_value(this.options.value.end.valueOf ? new Date(this.options.value.end) : 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","
"):'')+'