Implement calendar operations (create/edit/remove)

This commit is contained in:
Thomas Bruederli 2011-06-05 19:08:47 -06:00
parent 4d532e9a27
commit 95d7fa7c3a
16 changed files with 366 additions and 35 deletions

View file

@ -15,7 +15,7 @@
- List (Agenda) view
- Individual days selection
+ Show list of calendars in a (hideable) drawer
- View: 3.1: Folder list
+ View: 3.1: Folder list
- View: 3.2: Add / Remove / Rename / Share Folders
+ View: 3.6: Combined calendar view (Turn calendars on/off)
+ View: 3.7: Small month overview calendar

View file

@ -36,6 +36,7 @@ function rcube_calendar(settings)
/*** private vars ***/
var me = this;
var fcselector = '#calendar';
var day_clicked = day_clicked_ts = 0;
var ignore_click = false;
@ -158,14 +159,15 @@ function rcube_calendar(settings)
minWidth: 320,
width: 420
}).show();
/*
// add link for "more options" drop-down
$('<a>')
.attr('href', '#')
.html('More Options')
.addClass('dropdown-link')
.click(function(){ return false; })
.insertBefore($dialog.parent().find('.ui-dialog-buttonset').children().first());
*/
};
// bring up the event dialog (jquery-ui popup)
@ -461,7 +463,7 @@ function rcube_calendar(settings)
],
close: function(){
$dialog.dialog("destroy").hide();
$('#calendar').fullCalendar('refetchEvents');
$(fcselector).fullCalendar('refetchEvents');
}
}).show();
@ -475,7 +477,7 @@ function rcube_calendar(settings)
this.add_event = function() {
if (this.selected_calendar) {
var now = new Date();
var date = $('#calendar').fullCalendar('getDate') || now;
var date = $(fcselector).fullCalendar('getDate') || now;
date.setHours(now.getHours()+1);
date.setMinutes(0);
var end = new Date(date.getTime());
@ -601,6 +603,82 @@ function rcube_calendar(settings)
this.dismiss_link = null;
};
// opens a jquery UI dialog with event properties (or empty for creating a new calendar)
this.calendar_edit_dialog = function(calendar)
{
// close show dialog first
var $dialog = $("#calendarform").dialog('close');
if (!calendar)
calendar = { name:'', color:'cc0000' };
// reset form first
$('#calendarform > form').get(0).reset();
var name = $('#calendar-name').val(calendar.name);
var color = $('#calendar-color').val(calendar.color).miniColors('value', calendar.color);
// dialog buttons
var buttons = {};
buttons[rcmail.gettext('save', 'calendar')] = function() {
// TODO: do some input validation
if (!name.val() || name.val().length < 2) {
alert(rcmail.gettext('invalidcalendarproperties', 'calendar'));
name.select();
return;
}
// post data to server
var data = {
name: name.val(),
color: color.val().replace(/^#/, '')
};
if (calendar.id)
data.id = calendar.id;
rcmail.http_post('plugin.calendar', { action:(calendar.id ? 'edit' : 'new'), c:data });
$dialog.dialog("close");
};
buttons[rcmail.gettext('cancel', 'calendar')] = function() {
$dialog.dialog("close");
};
// open jquery UI dialog
$dialog.dialog({
modal: true,
resizable: true,
title: rcmail.gettext((calendar.id ? 'editcalendar' : 'createcalendar'), 'calendar'),
close: function() {
$dialog.dialog("destroy").hide();
},
buttons: buttons,
minWidth: 400,
width: 420
}).show();
name.select();
};
this.calendar_remove = function(calendar)
{
if (confirm(rcmail.gettext('deletecalendarconfirm', 'calendar'))) {
rcmail.http_post('plugin.calendar', { action:'remove', c:{ id:calendar.id } });
return true;
}
return false;
};
this.calendar_destroy_source = function(id)
{
if (this.calendars[id]) {
$(fcselector).fullCalendar('removeEventSource', this.calendars[id]);
$(rcmail.get_folder_li(id, 'rcmlical')).remove();
$('#edit-calendar option[value="'+id+'"]').remove();
delete this.calendars[id];
}
};
/*** startup code ***/
@ -633,7 +711,7 @@ function rcube_calendar(settings)
action = 'removeEventSource';
settings.hidden_calendars.push(id);
}
$('#calendar').fullCalendar(action, me.calendars[id]);
$(fcselector).fullCalendar(action, me.calendars[id]);
rcmail.save_pref({ name:'hidden_calendars', value:settings.hidden_calendars.join(',') });
}
}).data('id', id).get(0).checked = active;
@ -641,6 +719,7 @@ function rcube_calendar(settings)
$(li).click(function(e){
var id = $(this).data('id');
rcmail.select_folder(id, me.selected_calendar, 'rcmlical');
rcmail.enable_command('plugin.calendar-edit','plugin.calendar-remove', true);
me.selected_calendar = id;
}).data('id', id);
}
@ -652,7 +731,7 @@ function rcube_calendar(settings)
}
// initalize the fullCalendar plugin
$('#calendar').fullCalendar({
$(fcselector).fullCalendar({
header: {
left: 'prev,next today',
center: 'title',
@ -802,7 +881,7 @@ function rcube_calendar(settings)
var diff = (kw - base_kw) * 7 * 86400000;
// select monday of the chosen calendar week
var date = new Date(base_date.getTime() - day_off * 86400000 + diff);
$('#calendar').fullCalendar('gotoDate', date).fullCalendar('setDate', date).fullCalendar('changeView', 'agendaWeek');
$(fcselector).fullCalendar('gotoDate', date).fullCalendar('setDate', date).fullCalendar('changeView', 'agendaWeek');
$("#datepicker").datepicker('setDate', date);
window.setTimeout(init_week_events, 10);
}).css('cursor', 'pointer');
@ -817,7 +896,7 @@ function rcube_calendar(settings)
onSelect: function(dateText, inst) {
ignore_click = true;
var d = $("#datepicker").datepicker('getDate'); //parse_datetime('0:0', dateText);
$('#calendar').fullCalendar('gotoDate', d).fullCalendar('select', d, d, true);
$(fcselector).fullCalendar('gotoDate', d).fullCalendar('select', d, d, true);
window.setTimeout(init_week_events, 10);
},
onChangeMonthYear: function(year, month, inst) {
@ -826,14 +905,14 @@ function rcube_calendar(settings)
d.setYear(year);
d.setMonth(month - 1);
$("#datepicker").data('year', year).data('month', month);
//$('#calendar').fullCalendar('gotoDate', d).fullCalendar('setDate', d);
//$(fcselector).fullCalendar('gotoDate', d).fullCalendar('setDate', d);
},
}));
window.setTimeout(init_week_events, 10);
// react on fullcalendar buttons
var fullcalendar_update = function() {
var d = $('#calendar').fullCalendar('getDate');
var d = $(fcselector).fullCalendar('getDate');
$("#datepicker").datepicker('setDate', d);
window.setTimeout(init_week_events, 10);
};
@ -930,6 +1009,8 @@ function rcube_calendar(settings)
$('#recurrence-form-'+freq+', #recurrence-form-until').show();
});
$('#edit-recurrence-enddate').datepicker(datepicker_settings).click(function(){ $("#edit-recurrence-repeat-until").prop('checked', true) });
$('#calendar-color').miniColors();
// hide event dialog when clicking somewhere into document
$(document).bind('mousedown', dialog_check);
@ -942,6 +1023,11 @@ window.rcmail && rcmail.addEventListener('init', function(evt) {
// configure toobar buttons
rcmail.register_command('plugin.addevent', function(){ cal.add_event(); }, true);
// configure list operations
rcmail.register_command('plugin.calendar-create', function(){ cal.calendar_edit_dialog(null); }, true);
rcmail.register_command('plugin.calendar-edit', function(){ cal.calendar_edit_dialog(cal.calendars[cal.selected_calendar]); }, false);
rcmail.register_command('plugin.calendar-remove', function(){ cal.calendar_remove(cal.calendars[cal.selected_calendar]); }, false);
// export events
rcmail.register_command('plugin.export', function(){ rcmail.goto_url('plugin.export_events', { source:cal.selected_calendar }); }, true);
@ -950,6 +1036,7 @@ window.rcmail && rcmail.addEventListener('init', function(evt) {
// register callback commands
rcmail.addEventListener('plugin.display_alarms', function(alarms){ cal.display_alarms(alarms); });
rcmail.addEventListener('plugin.reload_calendar', function(p){ $('#calendar').fullCalendar('refetchEvents', cal.calendars[p.source]); });
rcmail.addEventListener('plugin.calendar_destroy_source', function(p){ cal.calendar_destroy_source(p.id); });
// let's go

View file

@ -50,7 +50,7 @@ class calendar extends rcube_plugin
}
// load localizations
$this->add_texts('localization/', $this->rc->action != 'plugin.event');
$this->add_texts('localization/', !$this->rc->action || $this->rc->task != 'calendar');
// load Calendar user interface which includes jquery-ui
$this->require_plugin('jqueryui');
@ -71,9 +71,9 @@ class calendar extends rcube_plugin
// register calendar actions
$this->register_action('index', array($this, 'calendar_view'));
$this->register_action('plugin.calendar', array($this, 'calendar_view'));
$this->register_action('plugin.event', array($this, 'event_action'));
$this->register_action('plugin.calendar', array($this, 'calendar_action'));
$this->register_action('plugin.load_events', array($this, 'load_events'));
$this->register_action('plugin.event', array($this, 'event'));
$this->register_action('plugin.export_events', array($this, 'export_events'));
$this->register_action('plugin.randomdata', array($this, 'generate_randomdata'));
$this->add_hook('keep_alive', array($this, 'keep_alive'));
@ -247,7 +247,7 @@ class calendar extends rcube_plugin
$field_class = 'rcmfd_category_' . str_replace(' ', '_', $name);
$category_remove = new html_inputfield(array('type' => 'button', 'value' => 'X', 'class' => 'button', 'onclick' => '$(this).parent().remove()', 'title' => $this->gettext('remove_category')));
$category_name = new html_inputfield(array('name' => "_categories[$key]", 'class' => $field_class, 'size' => 30));
$category_color = new html_inputfield(array('name' => "_colors[$key]", 'class' => $field_class, 'size' => 6));
$category_color = new html_inputfield(array('name' => "_colors[$key]", 'class' => "$field_class colors", 'size' => 6));
$categories_list .= html::div(null, $category_name->show($name) . '&nbsp;' . $category_color->show($color) . '&nbsp;' . $category_remove->show());
}
@ -261,16 +261,22 @@ class calendar extends rcube_plugin
$p['blocks']['categories']['options']['categories'] = array(
'content' => $new_category->show('') . '&nbsp;' . $add_category->show(),
);
$this->rc->output->add_script('function rcube_calendar_add_category(){
var name = $("#rcmfd_new_category").val();
if (name.length) {
var input = $("<input>").attr("type", "text").attr("name", "_categories[]").attr("size", 30).val(name);
var color = $("<input>").attr("type", "text").attr("name", "_colors[]").attr("size", 6).val("000000");
var color = $("<input>").attr("type", "text").attr("name", "_colors[]").attr("size", 6).addClass("colors").val("000000");
var button = $("<input>").attr("type", "button").attr("value", "X").addClass("button").click(function(){ $(this).parent().remove() });
$("<div>").append(input).append("&nbsp;").append(color).append("&nbsp;").append(button).appendTo("#calendarcategories");
color.miniColors();
}
}');
// include color picker
$this->include_script('lib/js/jquery.miniColors.min.js');
$this->include_stylesheet('skins/' .$this->rc->config->get('skin') . '/jquery.miniColors.css');
$this->rc->output->add_script('$("input.colors").miniColors()', 'docready');
}
}
@ -334,10 +340,43 @@ class calendar extends rcube_plugin
return $p;
}
/**
* Dispatcher for calendar actions initiated by the client
*/
function calendar_action()
{
$action = get_input_value('action', RCUBE_INPUT_POST);
$cal = get_input_value('c', RCUBE_INPUT_POST);
$success = $reload = false;
switch ($action) {
case "new":
$success = $this->driver->create_calendar($cal);
$reload = true;
break;
case "edit":
$success = $this->driver->edit_calendar($cal);
$reload = true;
break;
case "remove":
if ($success = $this->driver->remove_calendar($cal))
$this->rc->output->command('plugin.calendar_destroy_source', array('id' => $cal['id']));
break;
}
if ($success)
$this->rc->output->show_message('successfullysaved', 'confirmation');
else
$this->rc->output->show_message('calendar.errorsaving', 'error');
if ($success && $reload)
$this->rc->output->redirect('');
}
/**
* Dispatcher for event actions initiated by the client
*/
function event()
function event_action()
{
$action = get_input_value('action', RCUBE_INPUT_POST);
$event = get_input_value('e', RCUBE_INPUT_POST);

View file

@ -81,6 +81,24 @@ abstract class calendar_driver
*/
abstract function create_calendar($prop);
/**
* Update properties of an existing calendar
*
* @param array Hash array with calendar properties
* id: Calendar Identifier
* name: Calendar name
* color: The color of the calendar
* @return boolean True on success, Fales on failure
*/
abstract function edit_calendar($prop);
/**
* Delete the given calendar with all its contents
*
* @return boolean True on success, Fales on failure
*/
abstract function remove_calendar($prop);
/**
* Add a single event to the database
*

View file

@ -75,7 +75,7 @@ class database_driver extends calendar_driver
if (!empty($this->rc->user->ID)) {
$calendar_ids = array();
$result = $this->rc->db->query(
"SELECT * FROM " . $this->db_calendars . "
"SELECT *, calendar_id AS id FROM " . $this->db_calendars . "
WHERE user_id=?",
$this->rc->user->ID
);
@ -121,10 +121,59 @@ class database_driver extends calendar_driver
);
if ($result)
return $this->rc->db->insert_id($this->$sequence_calendars);
return $this->rc->db->insert_id($this->sequence_calendars);
return false;
}
/**
* Update properties of an existing calendar
*
* @see calendar_driver::edit_calendar()
*/
public function edit_calendar($prop)
{
$query = $this->rc->db->query(
"UPDATE " . $this->db_calendars . "
SET name=?, color=?
WHERE calendar_id=?
AND user_id=?",
$prop['name'],
$prop['color'],
$prop['id'],
$this->rc->user->ID
);
return $this->rc->db->affected_rows($query);
}
/**
* Delete the given calendar with all its contents
*
* @see calendar_driver::remove_calendar()
*/
public function remove_calendar($prop)
{
if (!$this->calendars[$prop['id']])
return false;
// delete all events of this calendar
$query = $this->rc->db->query(
"DELETE FROM " . $this->db_events . "
WHERE calendar_id=?",
$prop['id']
);
// TODO: also delete linked attachments
$query = $this->rc->db->query(
"DELETE FROM " . $this->db_calendars . "
WHERE calendar_id=?",
$prop['id']
);
return $this->rc->db->affected_rows($query);
}
/**
* Add a single event to the database
@ -699,8 +748,15 @@ class database_driver extends calendar_driver
*/
public function remove_category($name)
{
// TBD. alter events accordingly
return false;
$query = $this->rc->db->query(
"UPDATE " . $this->db_events . "
SET categories=''
WHERE categories=?
AND calendar_id IN (" . $this->calendar_ids . ")",
$name
);
return $this->rc->db->affected_rows($query);
}
/**
@ -708,8 +764,16 @@ class database_driver extends calendar_driver
*/
public function replace_category($oldname, $name, $color)
{
// TBD. alter events accordingly
return false;
$query = $this->rc->db->query(
"UPDATE " . $this->db_events . "
SET categories=?
WHERE categories=?
AND calendar_id IN (" . $this->calendar_ids . ")",
$name,
$oldname
);
return $this->rc->db->affected_rows($query);
}
}

View file

@ -54,6 +54,7 @@ class calendar_ui
{
$skin = $this->rc->config->get('skin');
$this->calendar->include_stylesheet('skins/' . $skin . '/fullcalendar.css');
$this->calendar->include_stylesheet('skins/' . $skin . '/jquery.miniColors.css');
}
/**
@ -62,6 +63,7 @@ class calendar_ui
public function addJS()
{
$this->calendar->include_script('lib/js/fullcalendar.js');
$this->calendar->include_script('lib/js/jquery.miniColors.min.js');
$this->calendar->include_script('calendar.js');
}

View file

@ -1,5 +1,5 @@
--- js/fullcalendar.js.orig 2011-06-04 15:45:44.000000000 -0400
+++ js/fullcalendar.js 2011-06-04 15:46:38.000000000 -0400
--- js/fullcalendar.js.orig 2011-06-04 13:45:44.000000000 -0600
+++ js/fullcalendar.js 2011-06-05 18:58:59.000000000 -0600
@@ -500,8 +500,8 @@
}
@ -11,7 +11,7 @@
}
@@ -897,7 +897,7 @@
@@ -897,15 +897,16 @@
}
@ -20,9 +20,10 @@
rangeStart = start;
rangeEnd = end;
cache = [];
@@ -905,7 +905,8 @@
var fetchID = ++currentFetchID;
var len = sources.length;
pendingSourceCnt = len;
- pendingSourceCnt = len;
+ pendingSourceCnt = typeof src == 'undefined' ? len : 1;
for (var i=0; i<len; i++) {
- fetchEventSource(sources[i], fetchID);
+ if (typeof src == 'undefined' || src == sources[i])

View file

@ -903,7 +903,7 @@ function EventManager(options, _sources) {
cache = [];
var fetchID = ++currentFetchID;
var len = sources.length;
pendingSourceCnt = len;
pendingSourceCnt = typeof src == 'undefined' ? len : 1;
for (var i=0; i<len; i++) {
if (typeof src == 'undefined' || src == sources[i])
fetchEventSource(sources[i], fetchID);

View file

@ -0,0 +1,17 @@
// http://plugins.jquery.com/project/jQueryMiniColors
if(jQuery)(function($){$.extend($.fn,{miniColors:function(o,data){var create=function(input,o,data){var color=cleanHex(input.val());if(!color)color='FFFFFF';var hsb=hex2hsb(color);var trigger=$('<a class="miniColors-trigger" style="background-color: #'+color+'" href="#"></a>');trigger.insertAfter(input);input.addClass('miniColors').attr('maxlength',7).attr('autocomplete','off');input.data('trigger',trigger);input.data('hsb',hsb);if(o.change)input.data('change',o.change);if(o.readonly)input.attr('readonly',true);if(o.disabled)disable(input);trigger.bind('click.miniColors',function(event){event.preventDefault();input.trigger('focus');});input.bind('focus.miniColors',function(event){show(input);});input.bind('blur.miniColors',function(event){var hex=cleanHex(input.val());input.val(hex?'#'+hex:'');});input.bind('keydown.miniColors',function(event){if(event.keyCode===9)hide(input);});input.bind('keyup.miniColors',function(event){var filteredHex=input.val().replace(/[^A-F0-9#]/ig,'');input.val(filteredHex);if(!setColorFromInput(input)){input.data('trigger').css('backgroundColor','#FFF');}});input.bind('paste.miniColors',function(event){setTimeout(function(){input.trigger('keyup');},5);});};var destroy=function(input){hide();input=$(input);input.data('trigger').remove();input.removeAttr('autocomplete');input.removeData('trigger');input.removeData('selector');input.removeData('hsb');input.removeData('huePicker');input.removeData('colorPicker');input.removeData('mousebutton');input.removeData('moving');input.unbind('click.miniColors');input.unbind('focus.miniColors');input.unbind('blur.miniColors');input.unbind('keyup.miniColors');input.unbind('keydown.miniColors');input.unbind('paste.miniColors');$(document).unbind('mousedown.miniColors');$(document).unbind('mousemove.miniColors');};var enable=function(input){input.attr('disabled',false);input.data('trigger').css('opacity',1);};var disable=function(input){hide(input);input.attr('disabled',true);input.data('trigger').css('opacity',.5);};var show=function(input){if(input.attr('disabled'))return false;hide();var selector=$('<div class="miniColors-selector"></div>');selector.append('<div class="miniColors-colors" style="background-color: #FFF;"><div class="miniColors-colorPicker"></div></div>');selector.append('<div class="miniColors-hues"><div class="miniColors-huePicker"></div></div>');selector.css({top:input.is(':visible')?input.offset().top+input.outerHeight():input.data('trigger').offset().top+input.data('trigger').outerHeight(),left:input.is(':visible')?input.offset().left:input.data('trigger').offset().left,display:'none'}).addClass(input.attr('class'));var hsb=input.data('hsb');selector.find('.miniColors-colors').css('backgroundColor','#'+hsb2hex({h:hsb.h,s:100,b:100}));var colorPosition=input.data('colorPosition');if(!colorPosition)colorPosition=getColorPositionFromHSB(hsb);selector.find('.miniColors-colorPicker').css('top',colorPosition.y+'px').css('left',colorPosition.x+'px');var huePosition=input.data('huePosition');if(!huePosition)huePosition=getHuePositionFromHSB(hsb);selector.find('.miniColors-huePicker').css('top',huePosition.y+'px');input.data('selector',selector);input.data('huePicker',selector.find('.miniColors-huePicker'));input.data('colorPicker',selector.find('.miniColors-colorPicker'));input.data('mousebutton',0);$('BODY').append(selector);selector.fadeIn(100);selector.bind('selectstart',function(){return false;});$(document).bind('mousedown.miniColors',function(event){input.data('mousebutton',1);if($(event.target).parents().andSelf().hasClass('miniColors-colors')){event.preventDefault();input.data('moving','colors');moveColor(input,event);}
if($(event.target).parents().andSelf().hasClass('miniColors-hues')){event.preventDefault();input.data('moving','hues');moveHue(input,event);}
if($(event.target).parents().andSelf().hasClass('miniColors-selector')){event.preventDefault();return;}
if($(event.target).parents().andSelf().hasClass('miniColors'))return;hide(input);});$(document).bind('mouseup.miniColors',function(event){input.data('mousebutton',0);input.removeData('moving');});$(document).bind('mousemove.miniColors',function(event){if(input.data('mousebutton')===1){if(input.data('moving')==='colors')moveColor(input,event);if(input.data('moving')==='hues')moveHue(input,event);}});};var hide=function(input){if(!input)input='.miniColors';$(input).each(function(){var selector=$(this).data('selector');$(this).removeData('selector');$(selector).fadeOut(100,function(){$(this).remove();});});$(document).unbind('mousedown.miniColors');$(document).unbind('mousemove.miniColors');};var moveColor=function(input,event){var colorPicker=input.data('colorPicker');colorPicker.hide();var position={x:event.clientX-input.data('selector').find('.miniColors-colors').offset().left+$(document).scrollLeft()-5,y:event.clientY-input.data('selector').find('.miniColors-colors').offset().top+$(document).scrollTop()-5};if(position.x<=-5)position.x=-5;if(position.x>=144)position.x=144;if(position.y<=-5)position.y=-5;if(position.y>=144)position.y=144;input.data('colorPosition',position);colorPicker.css('left',position.x).css('top',position.y).show();var s=Math.round((position.x+5)*.67);if(s<0)s=0;if(s>100)s=100;var b=100-Math.round((position.y+5)*.67);if(b<0)b=0;if(b>100)b=100;var hsb=input.data('hsb');hsb.s=s;hsb.b=b;setColor(input,hsb,true);};var moveHue=function(input,event){var huePicker=input.data('huePicker');huePicker.hide();var position={y:event.clientY-input.data('selector').find('.miniColors-colors').offset().top+$(document).scrollTop()-1};if(position.y<=-1)position.y=-1;if(position.y>=149)position.y=149;input.data('huePosition',position);huePicker.css('top',position.y).show();var h=Math.round((150-position.y-1)*2.4);if(h<0)h=0;if(h>360)h=360;var hsb=input.data('hsb');hsb.h=h;setColor(input,hsb,true);};var setColor=function(input,hsb,updateInputValue){input.data('hsb',hsb);var hex=hsb2hex(hsb);if(updateInputValue)input.val('#'+hex);input.data('trigger').css('backgroundColor','#'+hex);if(input.data('selector'))input.data('selector').find('.miniColors-colors').css('backgroundColor','#'+hsb2hex({h:hsb.h,s:100,b:100}));if(input.data('change')){input.data('change').call(input,'#'+hex,hsb2rgb(hsb));}};var setColorFromInput=function(input){var hex=cleanHex(input.val());if(!hex)return false;var hsb=hex2hsb(hex);var currentHSB=input.data('hsb');if(hsb.h===currentHSB.h&&hsb.s===currentHSB.s&&hsb.b===currentHSB.b)return true;var colorPosition=getColorPositionFromHSB(hsb);var colorPicker=$(input.data('colorPicker'));colorPicker.css('top',colorPosition.y+'px').css('left',colorPosition.x+'px');var huePosition=getHuePositionFromHSB(hsb);var huePicker=$(input.data('huePicker'));huePicker.css('top',huePosition.y+'px');setColor(input,hsb,false);return true;};var getColorPositionFromHSB=function(hsb){var x=Math.ceil(hsb.s/.67);if(x<0)x=0;if(x>150)x=150;var y=150-Math.ceil(hsb.b/.67);if(y<0)y=0;if(y>150)y=150;return{x:x-5,y:y-5};}
var getHuePositionFromHSB=function(hsb){var y=150-(hsb.h/2.4);if(y<0)h=0;if(y>150)h=150;return{y:y-1};}
var cleanHex=function(hex){hex=hex.replace(/[^A-Fa-f0-9]/,'');if(hex.length==3){hex=hex[0]+hex[0]+hex[1]+hex[1]+hex[2]+hex[2];}
return hex.length===6?hex:null;};var hsb2rgb=function(hsb){var rgb={};var h=Math.round(hsb.h);var s=Math.round(hsb.s*255/100);var v=Math.round(hsb.b*255/100);if(s==0){rgb.r=rgb.g=rgb.b=v;}else{var t1=v;var t2=(255-s)*v/255;var t3=(t1-t2)*(h%60)/60;if(h==360)h=0;if(h<60){rgb.r=t1;rgb.b=t2;rgb.g=t2+t3;}
else if(h<120){rgb.g=t1;rgb.b=t2;rgb.r=t1-t3;}
else if(h<180){rgb.g=t1;rgb.r=t2;rgb.b=t2+t3;}
else if(h<240){rgb.b=t1;rgb.r=t2;rgb.g=t1-t3;}
else if(h<300){rgb.b=t1;rgb.g=t2;rgb.r=t2+t3;}
else if(h<360){rgb.r=t1;rgb.g=t2;rgb.b=t1-t3;}
else{rgb.r=0;rgb.g=0;rgb.b=0;}}
return{r:Math.round(rgb.r),g:Math.round(rgb.g),b:Math.round(rgb.b)};};var rgb2hex=function(rgb){var hex=[rgb.r.toString(16),rgb.g.toString(16),rgb.b.toString(16)];$.each(hex,function(nr,val){if(val.length==1)hex[nr]='0'+val;});return hex.join('');};var hex2rgb=function(hex){var hex=parseInt(((hex.indexOf('#')>-1)?hex.substring(1):hex),16);return{r:hex>>16,g:(hex&0x00FF00)>>8,b:(hex&0x0000FF)};};var rgb2hsb=function(rgb){var hsb={h:0,s:0,b:0};var min=Math.min(rgb.r,rgb.g,rgb.b);var max=Math.max(rgb.r,rgb.g,rgb.b);var delta=max-min;hsb.b=max;hsb.s=max!=0?255*delta/max:0;if(hsb.s!=0){if(rgb.r==max){hsb.h=(rgb.g-rgb.b)/delta;}else if(rgb.g==max){hsb.h=2+(rgb.b-rgb.r)/delta;}else{hsb.h=4+(rgb.r-rgb.g)/delta;}}else{hsb.h=-1;}
hsb.h*=60;if(hsb.h<0){hsb.h+=360;}
hsb.s*=100/255;hsb.b*=100/255;return hsb;};var hex2hsb=function(hex){var hsb=rgb2hsb(hex2rgb(hex));if(hsb.s===0)hsb.h=360;return hsb;};var hsb2hex=function(hsb){return rgb2hex(hsb2rgb(hsb));};switch(o){case'readonly':$(this).each(function(){$(this).attr('readonly',data);});return $(this);break;case'disabled':$(this).each(function(){if(data){disable($(this));}else{enable($(this));}});return $(this);case'value':$(this).each(function(){$(this).val(data).trigger('keyup');});return $(this);break;case'destroy':$(this).each(function(){destroy($(this));});return $(this);default:if(!o)o={};$(this).each(function(){if($(this)[0].tagName.toLowerCase()!=='input')return;if($(this).data('trigger'))return;create($(this),o,data);});return $(this);}}});})(jQuery);

View file

@ -17,7 +17,7 @@ $labels = array();
// config
$labels['default_view'] = 'Ansicht';
$labels['time_format'] = 'Zeitformatierung';
$labels['timeslots'] = 'Zeitfenster pro Stunde';
$labels['timeslots'] = 'Zeitraster pro Stunde';
$labels['first_day'] = 'Erster Wochentag';
// calendar

View file

@ -17,6 +17,9 @@ $labels['calendars'] = 'Calendars';
$labels['category'] = 'Category';
$labels['categories'] = 'Categories';
$labels['createcalendar'] = 'Create new calendar';
$labels['editcalendar'] = 'Edit calendar properties';
$labels['name'] = 'Name';
$labels['color'] = 'Color';
$labels['day'] = 'Day';
$labels['week'] = 'Week';
$labels['month'] = 'Month';
@ -87,9 +90,11 @@ $labels['tabattachments'] = 'Attachments';
// messages
$labels['deleteventconfirm'] = "Do you really want to delete this event?";
$labels['deletecalendarconfirm'] = "Do you really want to delete this calendar with all its events?";
$labels['errorsaving'] = "Failed to save changes";
$labels['operationfailed'] = "The requested operation failed";
$labels['invalideventdates'] = "Invalid dates entered! Please check your input.";
$labels['invalidcalendarproperties'] = "Invalid calendar properties! Please set a valid name.";
// recurrence form
$labels['repeat'] = 'Repeat';

View file

@ -207,7 +207,8 @@ pre {
}
#eventshow,
#eventedit {
#eventedit,
#calendarform {
display: none;
}
@ -219,6 +220,10 @@ pre {
text-align: center;
}
a.miniColors-trigger {
margin-top: -3px;
}
/* jQuery UI overrides */
#eventshow h1 {
@ -256,6 +261,7 @@ pre {
border-radius: 0;
}
div.form-section,
#eventshow div.event-section,
#eventtabs div.event-section {
margin-top: 0.2em;
@ -287,7 +293,8 @@ pre {
}
#eventshow label,
#eventedit label {
#eventedit label,
.form-section label {
display: inline-block;
min-width: 7em;
padding-right: 0.5em;

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 421 B

View file

@ -0,0 +1,65 @@
.miniColors-trigger {
height: 22px;
width: 22px;
background: url('images/minicolors-all.png') -170px 0 no-repeat;
vertical-align: middle;
margin: 0 .25em;
display: inline-block;
outline: none;
}
.miniColors-selector {
position: absolute;
width: 175px;
height: 150px;
background: #FFF;
border: solid 1px #BBB;
-moz-box-shadow: 0 0 6px rgba(0, 0, 0, .25);
-webkit-box-shadow: 0 0 6px rgba(0, 0, 0, .25);
box-shadow: 0 0 6px rgba(0, 0, 0, .25);
-moz-border-radius: 5px;
-webkit-border-radius: 5px;
border-radius: 5px;
padding: 5px;
z-index: 999999;
}
.miniColors-selector.black {
background: #000;
border-color: #000;
}
.miniColors-colors {
position: absolute;
top: 5px;
left: 5px;
width: 150px;
height: 150px;
background: url('images/minicolors-all.png') top left no-repeat;
cursor: crosshair;
}
.miniColors-hues {
position: absolute;
top: 5px;
left: 160px;
width: 20px;
height: 150px;
background: url('images/minicolors-all.png') -150px 0 no-repeat;
cursor: crosshair;
}
.miniColors-colorPicker {
position: absolute;
width: 11px;
height: 11px;
background: url('images/minicolors-all.png') -170px -28px no-repeat;
}
.miniColors-huePicker {
position: absolute;
left: -3px;
width: 26px;
height: 3px;
background: url('images/minicolors-all.png') -170px -24px no-repeat;
}

View file

@ -18,8 +18,8 @@
<roundcube:object name="plugin.calendar_list" id="calendarslist" />
</div>
<div class="boxfooter">
<roundcube:button command="plugin.createcalendar" type="link" title="calendar.createcalendar" class="buttonPas addgroup" classAct="button addgroup" content=" " />
<roundcube:button name="calendarmenulink" id="calendarmenulink" type="link" title="calendaractions" class="button groupactions" onclick="return false" content=" " />
<roundcube:button command="plugin.calendar-create" type="link" title="calendar.createcalendar" class="buttonPas addgroup" classAct="button addgroup" content=" " />
<roundcube:button name="calendaroptionslink" id="calendaroptionslink" type="link" title="calendaractions" class="button groupactions" onclick="rcmail_ui.show_popup('calendaroptions');return false" content=" " />
</div>
</div>
</div>
@ -27,6 +27,13 @@
<div id="calendar"></div>
</div>
<div id="calendaroptionsmenu" class="popupmenu">
<ul>
<li><roundcube:button command="plugin.calendar-edit" label="calendar.edit" classAct="active" /></li>
<li><roundcube:button command="plugin.calendar-remove" label="calendar.remove" classAct="active" /></li>
</ul>
</div>
<div id="eventshow">
<h1 id="event-title">Event Title</h1>
<div class="event-section" id="event-location">Location</div>
@ -163,9 +170,24 @@
<roundcube:object name="plugin.edit_recurring_warning" class="edit-recurring-warning" style="display:none" />
</div>
<div id="calendarform">
<form action="#">
<div class="form-section">
<label for="calendar-name"><roundcube:label name="calendar.name" /></label>
<input type="text" name="name" size="20" id="calendar-name" />
</div>
<div class="form-section">
<label for="calendar-color"><roundcube:label name="calendar.color" /></label>
<input type="text" name="color" size="6" id="calendar-color" />
</div>
</form>
</div>
<div id="alarm-snooze-dropdown" class="popupmenu">
<roundcube:object name="plugin.snooze_select" type="ul" />
</div>
<div id="calendartoolbar">
<roundcube:button command="plugin.addevent" type="link" class="buttonPas addevent" classAct="button addevent" classSel="button addeventSel" title="calendar.new_event" content=" " />
<roundcube:button command="plugin.print" type="link" class="buttonPas print" classAct="button print" classSel="button printSel" title="calendar.print" content=" " />
@ -183,6 +205,10 @@
<script type="text/javascript">
// use skin functions to handle popup-menus
rcube_init_mail_ui();
rcmail_ui.popups.calendaroptions = { id:'calendaroptionsmenu', above:1, obj:$('#calendaroptionsmenu') };
$(document).ready(function(e){
// initialize sidebar toggle
$('#sidebartoggle').click(function() {