diff --git a/plugins/calendar/TODO b/plugins/calendar/TODO index 2775202b..6646ce80 100644 --- a/plugins/calendar/TODO +++ b/plugins/calendar/TODO @@ -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 diff --git a/plugins/calendar/calendar.js b/plugins/calendar/calendar.js index 199a373b..929aa7a4 100644 --- a/plugins/calendar/calendar.js +++ b/plugins/calendar/calendar.js @@ -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 $('') .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 diff --git a/plugins/calendar/calendar.php b/plugins/calendar/calendar.php index 40f00f0c..bec70d15 100644 --- a/plugins/calendar/calendar.php +++ b/plugins/calendar/calendar.php @@ -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) . ' ' . $category_color->show($color) . ' ' . $category_remove->show()); } @@ -261,16 +261,22 @@ class calendar extends rcube_plugin $p['blocks']['categories']['options']['categories'] = array( 'content' => $new_category->show('') . ' ' . $add_category->show(), ); - + $this->rc->output->add_script('function rcube_calendar_add_category(){ var name = $("#rcmfd_new_category").val(); if (name.length) { var input = $("").attr("type", "text").attr("name", "_categories[]").attr("size", 30).val(name); - var color = $("").attr("type", "text").attr("name", "_colors[]").attr("size", 6).val("000000"); + var color = $("").attr("type", "text").attr("name", "_colors[]").attr("size", 6).addClass("colors").val("000000"); var button = $("").attr("type", "button").attr("value", "X").addClass("button").click(function(){ $(this).parent().remove() }); $("
").append(input).append(" ").append(color).append(" ").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); diff --git a/plugins/calendar/drivers/calendar_driver.php b/plugins/calendar/drivers/calendar_driver.php index be50e300..b0687728 100644 --- a/plugins/calendar/drivers/calendar_driver.php +++ b/plugins/calendar/drivers/calendar_driver.php @@ -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 * diff --git a/plugins/calendar/drivers/database/database_driver.php b/plugins/calendar/drivers/database/database_driver.php index ef807747..6394849a 100644 --- a/plugins/calendar/drivers/database/database_driver.php +++ b/plugins/calendar/drivers/database/database_driver.php @@ -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); } } diff --git a/plugins/calendar/lib/calendar_ui.php b/plugins/calendar/lib/calendar_ui.php index 1f7348fc..27914e58 100644 --- a/plugins/calendar/lib/calendar_ui.php +++ b/plugins/calendar/lib/calendar_ui.php @@ -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'); } diff --git a/plugins/calendar/lib/fullcalendar-rc.patch b/plugins/calendar/lib/fullcalendar-rc.patch index 8b5337d1..3a7543d1 100644 --- a/plugins/calendar/lib/fullcalendar-rc.patch +++ b/plugins/calendar/lib/fullcalendar-rc.patch @@ -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');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=$('
');selector.append('
');selector.append('
');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); \ No newline at end of file diff --git a/plugins/calendar/localization/de_DE.inc b/plugins/calendar/localization/de_DE.inc index f9d0881d..c1a6e0d4 100644 --- a/plugins/calendar/localization/de_DE.inc +++ b/plugins/calendar/localization/de_DE.inc @@ -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 diff --git a/plugins/calendar/localization/en_US.inc b/plugins/calendar/localization/en_US.inc index 8872f798..f44f5317 100644 --- a/plugins/calendar/localization/en_US.inc +++ b/plugins/calendar/localization/en_US.inc @@ -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'; diff --git a/plugins/calendar/skins/default/calendar.css b/plugins/calendar/skins/default/calendar.css index 975b9d63..56846e93 100644 --- a/plugins/calendar/skins/default/calendar.css +++ b/plugins/calendar/skins/default/calendar.css @@ -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; diff --git a/plugins/calendar/skins/default/images/minicolors-all.png b/plugins/calendar/skins/default/images/minicolors-all.png new file mode 100644 index 00000000..001ed888 Binary files /dev/null and b/plugins/calendar/skins/default/images/minicolors-all.png differ diff --git a/plugins/calendar/skins/default/images/minicolors-handles.gif b/plugins/calendar/skins/default/images/minicolors-handles.gif new file mode 100644 index 00000000..9aa9f758 Binary files /dev/null and b/plugins/calendar/skins/default/images/minicolors-handles.gif differ diff --git a/plugins/calendar/skins/default/jquery.miniColors.css b/plugins/calendar/skins/default/jquery.miniColors.css new file mode 100644 index 00000000..c6e3e456 --- /dev/null +++ b/plugins/calendar/skins/default/jquery.miniColors.css @@ -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; +} \ No newline at end of file diff --git a/plugins/calendar/skins/default/templates/calendar.html b/plugins/calendar/skins/default/templates/calendar.html index 1d20e522..a376b4e5 100644 --- a/plugins/calendar/skins/default/templates/calendar.html +++ b/plugins/calendar/skins/default/templates/calendar.html @@ -18,8 +18,8 @@
- - + +
@@ -27,6 +27,13 @@
+
+ +
+

Event Title

Location
@@ -163,9 +170,24 @@
+ +
+
+
+ + +
+
+ + +
+
+
+
+
@@ -183,6 +205,10 @@