Elastic: Various calendar UI elements and calendar printing

This commit is contained in:
Aleksander Machniak 2018-04-02 17:46:14 +00:00
parent abd0ea1b69
commit cbd1d83c3d
15 changed files with 735 additions and 257 deletions

View file

@ -73,11 +73,11 @@ function rcube_calendar_ui(settings)
// general datepicker settings
var datepicker_settings = {
// translate from fullcalendar format to datepicker format
dateFormat: settings['date_format'].replace(/M/g, 'm').replace(/mmmmm/, 'MM').replace(/mmm/, 'M').replace(/dddd/, 'DD').replace(/ddd/, 'D').replace(/yy/g, 'y'),
firstDay : settings['first_day'],
dayNamesMin: settings['days_short'],
monthNames: settings['months'],
monthNamesShort: settings['months'],
dateFormat: settings.date_format.replace(/M/g, 'm').replace(/mmmmm/, 'MM').replace(/mmm/, 'M').replace(/dddd/, 'DD').replace(/ddd/, 'D').replace(/yy/g, 'y'),
firstDay: settings.first_day,
// dayNamesMin: settings.days_short,
monthNames: settings.months,
monthNamesShort: settings.months,
changeMonth: false,
showOtherMonths: true,
selectOtherMonths: true
@ -110,7 +110,7 @@ function rcube_calendar_ui(settings)
titleFormat: {
month: 'MMMM yyyy',
week: settings.dates_long,
day: 'dddd ' + settings['date_long'],
day: 'dddd ' + settings.date_long,
table: settings.dates_long
},
listPage: 7, // advance one week in agenda view
@ -386,7 +386,7 @@ function rcube_calendar_ui(settings)
changed = parseISO8601(event.changed);
$('.event-created', $dialog).text(created ? format_datetime(created) : rcmail.gettext('unknown','calendar'));
$('.event-changed', $dialog).text(changed ? format_datetime(changed) : rcmail.gettext('unknown','calendar'));
$('#event-created-changed').show()
$('#event-created,#event-changed,#event-created-changed').show()
}
// create attachments list
@ -452,22 +452,22 @@ function rcube_calendar_ui(settings)
if (morelink) {
$('#event-attendees .event-text').append(morelink);
morelink.click(function(e){
rcmail.show_popup_dialog(
rcmail.simple_dialog(
'<div id="all-event-attendees" class="event-attendees">' + html + overflow + '</div>',
rcmail.gettext('tabattendees','calendar'),
null,
{ width:450, modal:false });
{width: 450, cancel_button: 'close'});
$('#all-event-attendees a.mailtolink').click(event_attendee_click);
return false;
})
});
}
}
if (mystatus && !rsvp) {
$('#event-partstat').show().find('.changersvp')
$('#event-partstat').show().find('.changersvp, .event-text')
.removeClass('accepted tentative declined delegated needs-action unknown')
.addClass(mystatus)
.find('.event-text')
.addClass(mystatus);
$('#event-partstat').find('.event-text')
.text(rcmail.gettext('status' + mystatus, 'libcalendaring'));
}
@ -511,15 +511,13 @@ function rcube_calendar_ui(settings)
});
}
if (!buttons.length) {
buttons.push({
text: rcmail.gettext('close', 'calendar'),
'class': 'cancel',
click: function() {
$dialog.dialog('close');
}
});
}
buttons.push({
text: rcmail.gettext('close', 'calendar'),
'class': 'cancel',
click: function() {
$dialog.dialog('close');
}
});
// open jquery UI dialog
$dialog.dialog({
@ -2509,7 +2507,7 @@ function rcube_calendar_ui(settings)
if (action == 'remove' && cal.group != 'shared' && !_is_organizer && _is_attendee) {
decline = true;
checked = event.status != 'CANCELLED' ? checked : '';
html += '<div class="message">' +
html += '<div class="message dialog-message ui alert boxwarning">' +
'<label><input class="confirm-attendees-decline" type="checkbox"' + checked + ' value="1" name="decline" />&nbsp;' +
rcmail.gettext('itipdeclineevent', 'calendar') +
'</label></div>';
@ -2517,7 +2515,7 @@ function rcube_calendar_ui(settings)
else if (_is_organizer) {
notify = true;
if (settings.itip_notify & 2) {
html += '<div class="message">' +
html += '<div class="message dialog-message ui alert boxwarning">' +
'<label><input class="confirm-attendees-donotify" type="checkbox"' + checked + ' value="1" name="notify" />&nbsp;' +
rcmail.gettext((action == 'remove' ? 'sendcancellation' : 'sendnotifications'), 'calendar') +
'</label></div>';
@ -2538,13 +2536,12 @@ function rcube_calendar_ui(settings)
future_disabled = ' disabled';
}
html += '<div class="message"><span class="ui-icon ui-icon-alert"></span>' +
rcmail.gettext(message_label, 'calendar') + '</div>' +
html += '<div class="message dialog-message ui alert boxwarning">' + rcmail.gettext(message_label, 'calendar') + '</div>' +
'<div class="savemode">' +
'<a href="#current" class="button">' + rcmail.gettext('currentevent', 'calendar') + '</a>' +
'<a href="#future" class="button' + future_disabled + '">' + rcmail.gettext('futurevents', 'calendar') + '</a>' +
'<a href="#all" class="button">' + rcmail.gettext('allevents', 'calendar') + '</a>' +
(action != 'remove' ? '<a href="#new" class="button">' + rcmail.gettext('saveasnew', 'calendar') + '</a>' : '') +
'<a href="#current" class="button btn btn-secondary">' + rcmail.gettext('currentevent', 'calendar') + '</a>' +
'<a href="#future" class="button btn btn-secondary' + future_disabled + '">' + rcmail.gettext('futurevents', 'calendar') + '</a>' +
'<a href="#all" class="button btn btn-secondary">' + rcmail.gettext('allevents', 'calendar') + '</a>' +
(action != 'remove' ? '<a href="#new" class="button btn btn-secondary">' + rcmail.gettext('saveasnew', 'calendar') + '</a>' : '') +
'</div>';
}
@ -4132,6 +4129,12 @@ function rcube_calendar_ui(settings)
} // end rcube_calendar class
// Update layout after initialization
// In devel mode we have to wait until all styles are applied by less
if (rcmail.env.devel_mode && window.less) {
less.pageLoadFinished.then(function() { $(window).resize(); });
}
/* calendar plugin initialization */
window.rcmail && rcmail.addEventListener('init', function(evt) {
// configure toolbar buttons
@ -4197,4 +4200,54 @@ window.rcmail && rcmail.addEventListener('init', function(evt) {
// show toolbar
$('#toolbar').show();
// Elastic mods
if ($('#calendar').data('elastic-mode')) {
var selector = $('<div class="btn-group btn-group-toggle" role="group">').appendTo('.fc-header-left'),
nav = $('<div class="btn-group btn-group-toggle" role="group">').appendTo('.fc-header-right');
$('.fc-header-left > span').each(function() {
var cl = 'btn btn-secondary', btn = $(this);
if (btn.is('.fc-state-active')) {
cl += ' active';
}
$('<button>').attr({'class': cl}).text(btn.text())
.appendTo(selector)
.on('click', function() {
selector.children('.active').removeClass('active');
$(this).addClass('active');
btn.click();
});
});
$.each(['prev', 'today', 'next'], function() {
var btn = $('.fc-header-right').find('.fc-button-' + this);
$('<button>').attr({'class': 'btn btn-secondary'})
.text(btn.text()).appendTo(nav).on('click', function() { btn.click(); });
});
$('#timezone-display').appendTo($('.fc-header-center')).removeClass('hidden');
$('#agendaoptions').detach().insertAfter('table.fc-header');
// Mobile header title
if (window.MutationObserver) {
var observer,
title = $('.fc-header-title'),
mobile_header = $('#layout > .content > .header > .header-title'),
callback = function() {
var text = title.text();
mobile_header.html('').append([
$('<span class="title">').text(text),
$('<span class="tz">').text($('#timezone-display').text())
]);
};
// update the header when something changes on the calendar title
observer = new MutationObserver(callback);
observer.observe(title[0], {childList: true, subtree: true});
// initialize the header
callback();
}
}
});

View file

@ -36,7 +36,7 @@ class calendar_ui
$this->rc = $cal->rc;
$this->screen = $this->rc->task == 'calendar' ? ($this->rc->action ? $this->rc->action: 'calendar') : 'other';
}
/**
* Calendar UI initialization and requests handlers
*/
@ -44,7 +44,7 @@ class calendar_ui
{
if ($this->ready) // already done
return;
// add taskbar button
$this->cal->add_button(array(
'command' => 'calendar',
@ -56,8 +56,10 @@ class calendar_ui
), 'taskbar');
// load basic client script
$this->cal->include_script('calendar_base.js');
if ($this->rc->action != 'print') {
$this->cal->include_script('calendar_base.js');
}
$skin_path = $this->cal->local_skin_path();
$this->cal->include_stylesheet($skin_path . '/calendar.css');
@ -92,7 +94,7 @@ class calendar_ui
$this->cal->register_handler('plugin.edit_recurrence_sync', array($this, 'edit_recurrence_sync'));
$this->cal->register_handler('plugin.edit_recurring_warning', array($this, 'recurring_event_warning'));
$this->cal->register_handler('plugin.event_rsvp_buttons', array($this, 'event_rsvp_buttons'));
$this->cal->register_handler('plugin.angenda_options', array($this, 'angenda_options'));
$this->cal->register_handler('plugin.agenda_options', array($this, 'agenda_options'));
$this->cal->register_handler('plugin.events_import_form', array($this, 'events_import_form'));
$this->cal->register_handler('plugin.events_export_form', array($this, 'events_export_form'));
$this->cal->register_handler('plugin.object_changelog_table', array('libkolab', 'object_changelog_table'));
@ -329,30 +331,35 @@ class calendar_ui
}
/**
*
* Render a HTML for agenda options form
*/
function angenda_options($attrib = array())
function agenda_options($attrib = array())
{
$attrib += array('id' => 'agendaoptions');
$attrib['style'] .= 'display:none';
$select_range = new html_select(array('name' => 'listrange', 'id' => 'agenda-listrange', 'class' => 'form-control'));
$select_range->add(1 . ' ' . preg_replace('/\(.+\)/', '', $this->cal->lib->gettext('days')), $days);
foreach (array(2,5,7,14,30,60,90,180,365) as $days)
$select_range->add($days . ' ' . preg_replace('/\(|\)/', '', $this->cal->lib->gettext('days')), $days);
$html .= html::label('agenda-listrange', $this->cal->gettext('listrange'));
$html .= $select_range->show($this->rc->config->get('calendar_agenda_range', $this->cal->defaults['calendar_agenda_range']));
$html = html::span('input-group',
html::label(array('for' => 'agenda-listrange', 'class' => 'input-group-prepend'),
html::span('input-group-text', $this->cal->gettext('listrange')))
. $select_range->show($this->rc->config->get('calendar_agenda_range', $this->cal->defaults['calendar_agenda_range']))
);
$select_sections = new html_select(array('name' => 'listsections', 'id' => 'agenda-listsections', 'class' => 'form-control'));
$select_sections->add('---', '');
foreach (array('day' => 'libcalendaring.days', 'week' => 'libcalendaring.weeks', 'month' => 'libcalendaring.months', 'smart' => 'calendar.smartsections') as $val => $label)
$select_sections->add(preg_replace('/\(|\)/', '', ucfirst($this->rc->gettext($label))), $val);
$html .= html::span('spacer', '&nbsp;');
$html .= html::label('agenda-listsections', $this->cal->gettext('listsections'));
$html .= $select_sections->show($this->rc->config->get('calendar_agenda_sections', $this->cal->defaults['calendar_agenda_sections']));
$html .= html::span('input-group',
html::label(array('for' => 'agenda-listsections', 'class' => 'input-group-prepend'),
html::span('input-group-text', $this->cal->gettext('listsections')))
. $select_sections->show($this->rc->config->get('calendar_agenda_sections', $this->cal->defaults['calendar_agenda_sections']))
);
return html::div($attrib, $html);
}
@ -479,7 +486,7 @@ class calendar_ui
*/
function edit_attendees_notify($attrib = array())
{
$checkbox = new html_checkbox(array('name' => '_notify', 'id' => 'edit-attendees-donotify', 'value' => 1));
$checkbox = new html_checkbox(array('name' => '_notify', 'id' => 'edit-attendees-donotify', 'value' => 1, 'class' => 'pretty-checkbox'));
return html::div($attrib, html::label(null, $checkbox->show(1) . ' ' . $this->cal->gettext('sendnotifications')));
}
@ -488,7 +495,7 @@ class calendar_ui
*/
function edit_recurrence_sync($attrib = array())
{
$checkbox = new html_checkbox(array('name' => '_start_sync', 'value' => 1));
$checkbox = new html_checkbox(array('name' => '_start_sync', 'value' => 1, 'class' => 'pretty-checkbox'));
return html::div($attrib, html::label(null, $checkbox->show(1) . ' ' . $this->cal->gettext('eventstartsync')));
}
@ -498,14 +505,14 @@ class calendar_ui
function recurring_event_warning($attrib = array())
{
$attrib['id'] = 'edit-recurring-warning';
$radio = new html_radiobutton(array('name' => '_savemode', 'class' => 'edit-recurring-savemode'));
$form = html::label(null, $radio->show('', array('value' => 'current')) . $this->cal->gettext('currentevent')) . ' ' .
html::label(null, $radio->show('', array('value' => 'future')) . $this->cal->gettext('futurevents')) . ' ' .
html::label(null, $radio->show('all', array('value' => 'all')) . $this->cal->gettext('allevents')) . ' ' .
html::label(null, $radio->show('', array('value' => 'new')) . $this->cal->gettext('saveasnew'));
return html::div($attrib, html::div('message', html::span('ui-icon ui-icon-alert', '') . $this->cal->gettext('changerecurringeventwarning')) . html::div('savemode', $form));
return html::div($attrib, html::div('message', $this->cal->gettext('changerecurringeventwarning')) . html::div('savemode', $form));
}
/**
@ -525,8 +532,11 @@ class calendar_ui
}
$input = new html_inputfield(array(
'type' => 'file', 'name' => '_data', 'size' => $attrib['uploadfieldsize'],
'accept' => $accept));
'type' => 'file',
'name' => '_data',
'size' => $attrib['uploadfieldsize'],
'accept' => $accept
));
$select = new html_select(array('name' => '_range', 'id' => 'event-import-range'));
$select->add(array(
@ -539,28 +549,32 @@ class calendar_ui
),
array('1','2','3','6','12',0));
$html .= html::div('form-section',
html::div(null, $input->show()) .
html::div('hint', $this->rc->gettext(array('name' => 'maxuploadsize', 'vars' => array('size' => $max_filesize))))
$html = html::div('form-section form-group row',
html::label(array('class' => 'col-sm-4 col-form-label', 'for' => 'importfile'), rcube::Q($this->rc->gettext('importfromfile')))
. html::div('col-sm-8', $input->show()
. html::div('hint', $this->rc->gettext(array('id' => 'importfile', 'name' => 'maxuploadsize', 'vars' => array('size' => $max_filesize)))))
);
$html .= html::div('form-section',
html::label('event-import-calendar', $this->cal->gettext('calendar')) .
$this->calendar_select(array('name' => 'calendar', 'id' => 'event-import-calendar'))
$html .= html::div('form-section form-group row',
html::label(array('for' => 'event-import-calendar', 'class' => 'col-form-label col-sm-4'), $this->cal->gettext('calendar'))
. html::div('col-sm-8', $this->calendar_select(array('name' => 'calendar', 'id' => 'event-import-calendar')))
);
$html .= html::div('form-section',
html::label('event-import-range', $this->cal->gettext('importrange')) .
$select->show(1)
$html .= html::div('form-section form-group row',
html::label(array('for' => 'event-import-range', 'class' => 'col-form-label col-sm-4'), $this->cal->gettext('importrange'))
. html::div('col-sm-8', $select->show(1))
);
$this->rc->output->add_gui_object('importform', $attrib['id']);
$this->rc->output->add_label('import');
return html::tag('form', array('action' => $this->rc->url(array('task' => 'calendar', 'action' => 'import_events')),
'method' => "post", 'enctype' => 'multipart/form-data', 'id' => $attrib['id']),
$html
);
return html::tag('p', null, $this->cal->gettext('importtext'))
. html::tag('form', array(
'action' => $this->rc->url(array('task' => 'calendar', 'action' => 'import_events')),
'method' => 'post',
'enctype' => 'multipart/form-data',
'id' => $attrib['id']
), $html);
}
/**
@ -593,8 +607,8 @@ class calendar_ui
html::label(array('for' => 'event-export-range', 'class' => 'col-sm-4 col-form-label'), $this->cal->gettext('exportrange'))
. html::div('col-sm-8', $select->show(0) . html::span(array('style'=>'display:none'), $startdate->show())));
$checkbox = new html_checkbox(array('name' => 'attachments', 'id' => 'event-export-attachments', 'value' => 1));
$html .= html::div('form-section form-group row',
$checkbox = new html_checkbox(array('name' => 'attachments', 'id' => 'event-export-attachments', 'value' => 1, 'class' => 'form-check-input pretty-checkbox'));
$html .= html::div('form-section form-check row',
html::label(array('for' => 'event-export-attachments', 'class' => 'col-sm-4 col-form-label'), $this->cal->gettext('exportattachments'))
. html::div('col-sm-8', $checkbox->show(1)));

View file

@ -260,6 +260,7 @@ $labels['importsuccess'] = 'Successfully imported $nr events';
$labels['importnone'] = 'No events found to be imported';
$labels['importerror'] = 'An error occured while importing';
$labels['aclnorights'] = 'You do not have administrator rights on this calendar.';
$labels['importtext'] = 'You can upload events in <a href="https://wikipedia.org/wiki/ICalendar">iCalendar</a> format (.ics).';
$labels['changeeventconfirm'] = 'Change event';
$labels['removeeventconfirm'] = 'Delete event';
@ -290,7 +291,6 @@ $labels['revisionrestoreconfirm'] = 'Do you really want to restore revision $rev
$labels['objectrestoresuccess'] = 'Revision $rev successfully restored';
$labels['objectrestoreerror'] = 'Failed to restore the old revision';
// (hidden) titles and labels for accessibility annotations
$labels['arialabelminical'] = 'Calendar date selection';
$labels['arialabelcalendarview'] = 'Calendar view';

View file

@ -166,11 +166,38 @@ window.rcmail && rcmail.addEventListener('init', function(evt) {
}, 20);
}
});
// activate settings form
$('#propdescription').change(function(){
showdesc = this.checked;
fc.fullCalendar('render');
});
var selector = $('#calendar').data('view-selector');
if (selector) {
selector = $('#' + selector);
$('.fc-header-right > span').each(function() {
var cl = 'btn btn-secondary', btn = $(this);
if (btn.is('.fc-state-active')) {
cl += ' active';
}
$('<button>').attr({'class': cl})
.text(btn.text())
.appendTo(selector)
.on('click', function() {
selector.children('.active').removeClass('active');
$(this).addClass('active');
btn.click();
});
});
};
// Update layout after initialization
// In devel mode we have to wait until all styles are applied by less
if (rcmail.env.devel_mode && window.less) {
less.pageLoadFinished.then(function() { $(window).resize(); });
}
});

View file

@ -37,7 +37,7 @@
</div>
<!-- calendar -->
<div class="content selected" role="main">
<div class="content selected no-navbar" role="main">
<h2 id="aria-label-toolbar" class="voice"><roundcube:label name="arialabeltoolbar" /></h2>
<div class="header" role="toolbar" aria-labelledby="aria-label-toolbar">
<a class="button icon back-sidebar-button folders" href="#sidebar" data-hidden="big"><span class="inner"><roundcube:label name="calendar.calendars" /></span></a>
@ -47,7 +47,7 @@
<roundcube:button command="addevent" type="link"
class="button create disabled" classAct="button create"
label="create" title="calendar.new_event" innerClass="inner" />
<roundcube:button command="print" type="link"
<roundcube:button command="print" type="link" data-hidden="small"
class="button print disabled" classAct="button print"
label="calendar.print" title="calendar.printtitle" innerClass="inner" />
<span class="spacer"></span>
@ -70,8 +70,13 @@
-->
</div>
<h2 id="aria-label-calendarview" class="voice"><roundcube:label name="calendar.arialabelcalendarview" /></h2>
<div id="calendar" class="content" role="main" aria-labelledby="aria-label-calendarview">
<roundcube:object name="plugin.angenda_options" id="agendaoptions" />
<div id="calendar" class="content" role="main" aria-labelledby="aria-label-calendarview" data-elastic-mode="true">
<roundcube:object name="plugin.agenda_options" id="agendaoptions" />
</div>
<div class="footer toolbar" role="toolbar" data-hidden="big">
<a href="#" class="button prev" onclick="$('.fc-button-prev').click()"><span class="inner"><roundcube:label name="previous" /></span></a>
<a href="#" class="button today" onclick="$('.fc-button-today').click()"><span class="inner"><roundcube:label name="today" /></span></a>
<a href="#" class="button next" onclick="$('.fc-button-next').click()"><span class="inner"><roundcube:label name="next" /></span></a>
</div>
</div>
@ -100,11 +105,11 @@
<label class="col-sm-4 col-form-label"><roundcube:label name="calendar.alarms" /></label>
<span class="event-text col-sm-8 form-control-plaintext"></span>
</div>
<div id="event-partstat" class="form-group row">
<div id="event-partstat" class="form-group row event-partstat">
<label class="col-sm-4 col-form-label"><roundcube:label name="calendar.mystatus" /></label>
<span class="event-text col-sm-8"></span>
<span class="changersvp" role="button" tabindex="0" title="<roundcube:label name='calendar.changepartstat' />">
<a class="iconbutton edit"><roundcube:label name='calendar.changepartstat' /></a>
<span class="col-sm-8 form-control-plaintext">
<span class="event-text rsvp-status"></span>
<a class="changersvp button edit" href="#" title="<roundcube:label name='calendar.changepartstat' />"><span class="inner"><roundcube:label name='calendar.changepartstat' /></span></a>
</span>
</div>
<div id="event-calendar" class="form-group row">
@ -127,11 +132,11 @@
<label class="col-sm-4 col-form-label"><roundcube:label name="calendar.priority" /></label>
<span class="event-text col-sm-8 form-control-plaintext"></span>
</div>
<div id="event-created" class="form-group row">
<div id="event-created" class="form-group row faded">
<label class="col-sm-4 col-form-label"><roundcube:label name="calendar.created" /></label>
<span class="event-text event-created col-sm-8 form-control-plaintext"></span>
</div>
<div id="event-changed" class="form-group row">
<div id="event-changed" class="form-group row faded">
<label class="col-sm-4 col-form-label"><roundcube:label name="calendar.changed" /></label>
<span class="event-text event-changed col-sm-8 form-control-plaintext"></span>
</div>
@ -288,8 +293,8 @@
<roundcube:if condition="config:kolab_bonnie_api" />
<div id="eventhistory" class="popupmenu" aria-hidden="true">
<roundcube:object name="plugin.object_changelog_table" id="event-changelog-table" class="changelog-table" />
<div class="compare-button"><input type="button" class="button" value="<roundcube:label name='libkolab.compare' />" /></div>
<roundcube:object name="plugin.object_changelog_table" id="event-changelog-table" class="changelog-table" />
<div class="compare-button"><input type="button" class="button" value="<roundcube:label name='libkolab.compare' />" /></div>
</div>
<div id="eventdiff" class="popupmenu formcontent text-only">
@ -378,16 +383,4 @@
<roundcube:object name="plugin.calendar_css" folder-class="div.$class a.calname:before" folder-fallback-color="#161b1d" />
<script type="text/javascript">
$(document).ready(function() {
// TODO: $('#timezone-display').appendTo($('.fc-header-title')).removeClass('hidden');
});
// Update layout after initialization
// In devel mode we have to wait until all styles are applied by less
if (rcmail.env.devel_mode && window.less) {
less.pageLoadFinished.then(function() { $(window).resize(); });
}
</script>
<roundcube:include file="includes/footer.html" />

View file

@ -120,7 +120,7 @@
<fieldset id="event-panel-attendees">
<legend><roundcube:label name="calendar.tabattendees" /></legend>
<h3 id="aria-label-attendeestable" class="voice"><roundcube:label name="calendar.arialabeleventattendees" /></h3>
<roundcube:object name="plugin.attendees_list" id="edit-attendees-table" class="edit-attendees-table no-img table-sm"
<roundcube:object name="plugin.attendees_list" id="edit-attendees-table" class="edit-attendees-table no-img table table-sm"
coltitle="attendee" aria-labelledby="aria-label-attendeestable" />
<roundcube:object name="plugin.attendees_form" id="edit-attendees-form" />
<roundcube:include file="/templates/freebusylegend.html" />
@ -129,7 +129,7 @@
<fieldset id="event-panel-resources">
<legend><roundcube:label name="calendar.tabresources" /></legend>
<h3 id="aria-label-resourcestable" class="voice"><roundcube:label name="calendar.arialabeleventresources" /></h3>
<roundcube:object name="plugin.attendees_list" id="edit-resources-table" class="edit-attendees-table no-img table-sm"
<roundcube:object name="plugin.attendees_list" id="edit-resources-table" class="edit-attendees-table no-img table table-sm"
coltitle="resource" aria-labelledby="aria-label-resourcestable" />
<roundcube:object name="plugin.resources_form" id="edit-resources-form" />
<roundcube:include file="/templates/freebusylegend.html" />

View file

@ -1,28 +1,18 @@
<roundcube:object name="doctype" value="html5" />
<html>
<head>
<title><roundcube:object name="pagetitle" /></title>
</head>
<body class="calendarprint">
<roundcube:include file="includes/layout.html" />
<div id="printconfig" class="noprint">
<div class="calwidth">
<a href="#close" onclick="window.close()" class="rightalign"><roundcube:label name="close" /></a>
<span class="prop"><input type="button" id="printme" value="<roundcube:label name='print' />" onclick="window.print()"></span>
<span class="prop"><label><input type="checkbox" id="propdescription" checked="checked" /> <roundcube:label name="calendar.printdescriptions" /></label></span>
</div>
<div class="print-config">
<button class="btn btn-primary print" onclick="window.print()"><roundcube:label name='print' /></button>
<span class="prop">
<input type="checkbox" id="propdescription" checked="checked" class="pretty-checkbox" />
<label for="propdescription"><roundcube:label name="calendar.printdescriptions" /></label>
</span>
<div id="calendar-view-selector" class="btn-group btn-group-toggle" role="group"></div>
</div>
<roundcube:object name="message" id="message" class="noprint" />
<div id="calendar" class="calwidth"></div>
<div class="calwidth">
<roundcube:object name="plugin.calendar_list" activeonly="true" id="calendarlist" />
<br style="clear:both">
<div class="print-content">
<div id="calendar" data-view-selector="calendar-view-selector"></div>
</div>
<roundcube:object name="plugin.calendar_css" printmode="true" />
</body>
</html>
<roundcube:include file="includes/footer.html" />

View file

@ -57,7 +57,7 @@
<h2 id="aria-label-calendarview" class="voice"><roundcube:label name="calendar.arialabelcalendarview" /></h2>
<div id="calendar" role="main" aria-labelledby="aria-label-calendarview">
<roundcube:object name="plugin.angenda_options" class="boxfooter" id="agendaoptions" />
<roundcube:object name="plugin.agenda_options" class="boxfooter" id="agendaoptions" />
</div>
</div>

View file

@ -36,6 +36,10 @@
content: @fa-var-cube;
}
a.button.today:before {
.font-icon-regular(@fa-var-calendar);
}
.listing {
li {
& > div {
@ -141,6 +145,11 @@ fieldset.categories .input-group {
}
}
#calendar.content {
overflow: hidden !important; // fullcalendar widget implements scrolling on its own
position: relative;
}
.calendar-datepicker {
// overwrite jQuery-UI datepicker styles
.ui-datepicker {
@ -168,16 +177,47 @@ fieldset.categories .input-group {
}
// Fullcalendar styles
@color-calendar-border: @color-layout-border;
.fc {
flex: auto !important;
.fc-header {
tr {
background-color: @color-black-shade-bg;
}
}
.fc-header-left {
width: 25%;
span {
display: none;
}
}
.fc-header-center {
text-align: center;
h2 {
margin: 0;
color: @color-black-shade-text;
white-space: nowrap;
}
}
.fc-header-right {
width: 25%;
text-align: right;
span {
display: none;
}
}
.btn-group {
padding: .5rem;
}
.fc-header-title {
@ -187,9 +227,6 @@ fieldset.categories .input-group {
}
}
.fc-content {
}
.fc-view {
width: 100%;
overflow: hidden;
@ -199,13 +236,12 @@ fieldset.categories .input-group {
.fc-widget-header, // <th>, usually
.fc-widget-content { // <td>, usually
border: 1px solid #ddd;
border: 1px solid @color-calendar-border;
}
.fc-cell-overlay { // semi-transparent rectangle while dragging
background: #bce8f1;
opacity: .3;
filter: alpha(opacity=30); /* for IE */
}
// Buttons
@ -222,55 +258,16 @@ fieldset.categories .input-group {
}
// Our default prev/next buttons use HTML entities like &lsaquo; &rsaquo; &laquo; &raquo;
// and we'll try to make them look good cross-browser.
.fc-text-arrow {
margin: 0 .1em;
font-size: 2em;
}
.fc-button-prev .fc-text-arrow,
.fc-button-next .fc-text-arrow { // for &lsaquo; &rsaquo;
font-weight: bold;
}
// icon (for jquery ui)
.fc-button {
.fc-icon-wrap {
position: relative;
float: left;
top: 50%;
}
.ui-icon {
position: relative;
float: left;
margin-top: -50%;
}
}
// Button states
// borrowed from twitter bootstrap (http://twitter.github.com/bootstrap/)
.fc-state-highlight { // <td> today cell, TODO: add .fc-today to <th>
background: #fcf8e3;
background: tint(@color-main, 90%);
}
/*
.fc-state-default {
border: 1px solid;
background-color: #f5f5f5;
&.fc-corner-left { // non-theme
border-top-left-radius: 4px;
border-bottom-left-radius: 4px;
}
&.fc-corner-right { // non-theme
border-top-right-radius: 4px;
border-bottom-right-radius: 4px;
}
}
.fc-state-hover,
@ -297,6 +294,7 @@ fieldset.categories .input-group {
background-image: none;
opacity: 0.65;
}
*/
// Global Event Styles
@ -348,11 +346,7 @@ fieldset.categories .input-group {
}
.ui-resizable-handle {
display: block;
position: absolute;
z-index: 99999;
font-size: 300%;
line-height: 50%;
}
// Horizontal Events
@ -365,33 +359,23 @@ fieldset.categories .input-group {
.fc-ltr .fc-event-hori.fc-event-start,
.fc-rtl .fc-event-hori.fc-event-end {
border-left-width: 1px;
border-top-left-radius: 3px;
border-bottom-left-radius: 3px;
}
.fc-ltr .fc-event-hori.fc-event-end,
.fc-rtl .fc-event-hori.fc-event-start {
border-right-width: 1px;
border-top-right-radius: 3px;
border-bottom-right-radius: 3px;
}
// resizable
.fc-event-hori .ui-resizable-e {
top: 0 !important; // importants override pre jquery ui 1.7 styles
right: -3px !important;
width: 7px !important;
height: 100% !important;
cursor: e-resize;
}
.fc-event-hori {
.ui-resizable-e {
cursor: e-resize;
}
.fc-event-hori .ui-resizable-w {
top: 0 !important;
left: -3px !important;
width: 7px !important;
height: 100% !important;
cursor: w-resize;
.ui-resizable-w {
cursor: w-resize;
}
}
// Reusable Separate-border Table
@ -399,7 +383,6 @@ fieldset.categories .input-group {
.fc-border-separate {
border-collapse: separate;
th,
td {
border-width: 1px 0 0 1px;
@ -420,6 +403,11 @@ fieldset.categories .input-group {
}
}
.fc-event-date,
.fc-event-time {
white-space: nowrap;
}
// Month View, Basic Week View, Basic Day View
.fc-week-number {
@ -431,6 +419,10 @@ fieldset.categories .input-group {
}
}
.fc-day {
vertical-align: top;
}
.fc-grid {
th {
text-align: center;
@ -453,6 +445,7 @@ fieldset.categories .input-group {
// event styles
.fc-event-time {
font-weight: bold;
white-space: nowrap;
}
// right-to-left
@ -471,11 +464,7 @@ fieldset.categories .input-group {
text-decoration: none;
cursor: pointer;
padding: 1px;
}
.fc-first .fc-day-header,
.fc-week .fc-first {
border-left: 0;
color: @color-link !important;
}
// Agenda Week View, Agenda Day View
@ -496,6 +485,7 @@ fieldset.categories .input-group {
text-align: right;
white-space: nowrap;
font-weight: normal;
font-size: .9rem;
border-left: 0;
}
@ -503,7 +493,7 @@ fieldset.categories .input-group {
font-weight: bold;
}
.fc-agenda .fc-day-content {
.fc-day-content {
padding: 2px 2px 1px;
}
}
@ -533,12 +523,8 @@ fieldset.categories .input-group {
// divider (between all-day and slots)
.fc-agenda-divider-inner {
height: 2px;
height: 1px;
overflow: hidden;
.fc-widget-header & {
background: #eee;
}
}
// slot rows
@ -583,19 +569,16 @@ fieldset.categories .input-group {
&.fc-event-start {
border-top-width: 1px;
border-top-left-radius: 3px;
border-top-right-radius: 3px;
}
&.fc-event-end {
border-bottom-width: 1px;
border-bottom-left-radius: 3px;
border-bottom-right-radius: 3px;
}
.fc-event-time {
white-space: nowrap;
font-size: 10px;
font-weight: bold;
}
.fc-event-inner {
@ -636,7 +619,7 @@ fieldset.categories .input-group {
margin: 0;
padding: 0;
border: none;
border-top: 2px solid #3ec400;
border-top: 2px solid @color-success;
z-index: 999;
}
@ -644,9 +627,9 @@ fieldset.categories .input-group {
.fc-view-list,
.fc-view-table {
border: 1px solid #ccc; // TODO: border
border-left: 0;
border-bottom: 0;
border-top: 1px solid @color-layout-border;
width: auto;
.fc-list-header,
@ -654,6 +637,11 @@ fieldset.categories .input-group {
border-width: 0;
border-bottom-width: 1px;
padding: 3px 5px;
font-weight: bold;
}
.fc-event {
font-size: 1rem;
}
}
@ -664,7 +652,7 @@ fieldset.categories .input-group {
}
.fc-view-list .fc-last {
border-bottom-width: 0;
border-bottom: 0;
}
.fc-list-section .fc-event {
@ -679,7 +667,7 @@ fieldset.categories .input-group {
td {
padding: 2px;
border-bottom: 1px solid #ccc;
border-bottom: 1px solid @color-calendar-border;
}
td.fc-event-handle {
@ -692,15 +680,10 @@ fieldset.categories .input-group {
}
.fc-event-handle {
.fc-event-skin {
border-radius: 2px;
}
.fc-event-inner {
display: block;
width: 8px;
height: 10px;
border-radius: 2px;
}
}
@ -761,10 +744,239 @@ fieldset.categories .input-group {
.fc-icon-sensitive:before {
content: @fa-var-lock;
}
// remove redundant borders
.fc-first tbody .fc-day-header,
.fc-first .fc-day-header.fc-first,
.fc-week .fc-first {
border-left: 0;
}
.fc-agenda-days tbody .fc-last > *,
.fc-agenda-slots tr:last-child td,
.fc-week.fc-last .fc-day {
border-bottom: 0;
}
}
// fullcalendar style overrides for printing
.print-content {
.fc-header {
tr {
background-color: #fff;
}
}
.fc-header-center {
width: 100%;
h2 {
color: #000;
padding-bottom: .75rem;
font-size: 1.5rem !important;
}
}
.fc-agenda-gutter,
.fc-header-left,
.fc-header-right {
display: none !important;
}
.fc-view {
overflow: visible;
}
.fc-event-skin,
.fc-event-inner .fc-event-skin {
color: black;
background-color: #fff !important;
}
.fc-event-title {
font-weight: bold;
}
.fc-event-hori {
.fc-event-title {
font-weight: normal;
white-space: nowrap;
}
.fc-event-time {
white-space: nowrap;
font-weight: normal !important;
font-size: 10px;
padding-right: 0.6em;
}
}
.fc-grid .fc-event-time {
font-weight: normal !important;
padding-right: 0.3em;
}
.fc-event-cateories {
font-style: italic;
}
.fc-event-location {
font-size: 90%;
}
.fc-agenda-slots td div {
height: 1.4em;
}
.fc-widget-header,
.fc-mon, .fc-tue, .fc-wed, .fc-thu, .fc-fri {
background-color: #fff;
}
.fc-widget-header, .fc-widget-content {
border-color: @color-calendar-border;
}
.fc-view-list, .fc-view-table {
border: 0;
}
.fc-view-list div.fc-list-header,
.fc-view-table td.fc-list-header {
padding: 0.3em;
background: #fff;
font-weight: bold;
font-size: 1.2em;
color: #333;
border-color: @color-calendar-border;
border-style: solid;
border-width: 1px 0;
}
.fc-list-section .fc-event {
cursor: auto;
}
.fc-view-table {
tr.fc-event td,
tr.fc-event td.fc-event-handle {
border-color: @color-calendar-border;
padding-top: 0.5em;
padding-bottom: 0.5em;
}
tr.fc-last td {
border: 0;
}
tr.fc-event .fc-event-description {
padding-left: 2em;
padding-top: 0em;
}
col.fc-event-location {
width: 20%;
}
}
.fc-event-vert .fc-event-description {
font-size: 90%;
font-style: italic;
}
.fc-view-month .fc-event-hori .fc-event-inner {
background: #fff !important;
}
// add back borders removed in non-print view
.fc-agenda .fc-agenda-axis,
.fc-first .fc-day-header,
.fc-week .fc-first {
border-left: 1px solid @color-calendar-border;
}
.fc-agenda-days th:nth-last-child(2),
.fc-agenda-allday td,
.fc-agenda-slots td.fc-widget-content {
border-right: 1px solid @color-calendar-border;
}
.fc-agenda-days tr.fc-last > *,
.fc-week.fc-last .fc-day {
border-bottom: 1px solid @color-calendar-border;
}
}
body.task-calendar {
#print-layout {
#calendar-view-selector {
float: right;
padding-top: .25rem;
}
}
@media screen and (min-width: (@screen-width-small + 1px)) {
& > #layout > div.sidebar {
flex: 2 !important;
max-width: 400px;
}
}
// improve datepicker
.ui-datepicker {
td {
width: 12.5%;
}
.ui-datepicker-week-col {
color: @color-black-shade-border;
text-align: center;
}
}
.ui-datepicker-inline {
.ui-datepicker-week-col {
color: @color-link;
cursor: pointer;
}
.ui-datepicker-activerange {
background-color: @color-list-selected-background;
}
}
}
#timezone-display {
font-size: .9rem;
color: @color-black-shade-text;
}
#agendaoptions {
padding: 0 .5rem .5rem .5rem;
display: flex;
background-color: @color-black-shade-bg;
.input-group {
padding-right: .5rem;
flex-wrap: nowrap;
width: 50%;
&:last-child {
padding-right: 0;
}
}
select {
min-width: 7em;
}
.input-group-prepend {
overflow: hidden;
span {
display: block;
.overflow-ellipsis;
}
}
}
#eventshow {
@ -786,6 +998,78 @@ fieldset.categories .input-group {
.event-attendees {
margin-bottom: 1rem;
.attendee {
margin-right: .25rem;
}
}
.event-partstat {
& > span {
display: flex;
}
.rsvp-status {
&:before {
display: inline;
float: none;
}
}
.changersvp {
cursor: pointer;
font-size: 1.2rem;
margin-left: 1em;
&:before {
&:extend(.font-icon-class);
content: @fa-var-pen-square;
float: none;
display: inline;
line-height: 1;
}
}
.inner {
display: none;
}
}
.faded {
color: @color-black-shade-text;
}
}
#eventedit {
.edit-attendees-table td {
padding-top: .15rem;
&.role {
padding-left: 0;
width: 9em;
}
}
}
#fish-eye-view {
padding: 0;
border-bottom: 1px solid @color-calendar-border;
.fc-header {
display: none;
}
.fc-view {
position: initial !important;
}
.fc-agenda-days tr.fc-first th {
border-top: 0;
}
.fc-agenda-divider + div {
height: 100% !important;
overflow: initial !important;
}
}
@ -1138,7 +1422,8 @@ fieldset.categories .input-group {
flex: 4;
border: 1px solid @color-layout-border;
min-width: 300px;
justify-content: center;
justify-content: center;
.header {
border-bottom: 1px solid @color-layout-border;
display: flex;
@ -1184,3 +1469,86 @@ fieldset.categories .input-group {
border: 1px solid @color-layout-border !important;
}
}
@media screen and (max-width: @screen-width-small) {
.fc {
.fc-header-left {
display: block;
width: 100%;
padding: 0;
button {
flex: 1 1 auto;
border-radius: 0;
}
.btn-group {
padding: 0;
display: flex;
}
}
.fc-header-center,
.fc-header-right {
display: none;
}
}
#agendaoptions {
padding-top: .5rem;
}
.calendar-scheduler {
.schedule-range {
width: 100%;
}
}
}
@media screen and (min-width: (@screen-width-small + 1px)) and (max-width: 920px) {
.fc {
.fc-header {
display: block;
tr {
display: flex;
}
}
.fc-header-center {
.overflow-ellipsis;
flex: 1;
h2 {
font-size: 1rem;
line-height: 1;
padding-top: .75rem;
}
}
.fc-header-left,
.fc-header-right {
width: auto;
.btn {
padding-left: .5rem;
padding-right: .5rem;
}
}
}
}
.header-title {
position: relative;
.tz {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
line-height: 2;
font-size: .8rem;
font-weight: normal;
color: @color-black-shade-text;
}
}

View file

@ -106,46 +106,6 @@
color: #666;
font-style: italic;
}
&:before {
line-height: 1.1;
color: lighten(@color-black, 25%);
}
&.loading:before {
&:extend(.font-icon-class);
.animated-icon-class;
content: @fa-var-circle-notch;
line-height: 1;
}
&.declined:before {
&:extend(.font-icon-class);
content: @fa-var-ban;
color: @color-error;
}
&.tentative:before {
&:extend(.font-icon-class);
content: @fa-var-check-circle;
color: @color-warning;
}
&.accepted:before {
&:extend(.font-icon-class);
content: @fa-var-check-circle;
color: @color-success;
}
&.delegated:before {
&:extend(.font-icon-class);
content: @fa-var-share;
}
&.needs-action:before {
&:extend(.font-icon-class);
content: @fa-var-question-circle;
}
}
.folder-select {
@ -158,6 +118,50 @@
}
}
.rsvp-status {
&:before {
line-height: 1.1;
color: lighten(@color-black, 25%);
float: none;
display: inline;
}
&.loading:before {
&:extend(.font-icon-class);
.animated-icon-class;
content: @fa-var-circle-notch;
line-height: 1;
}
&.declined:before {
&:extend(.font-icon-class);
content: @fa-var-ban;
color: @color-error;
}
&.tentative:before {
&:extend(.font-icon-class);
content: @fa-var-check-circle;
color: @color-warning;
}
&.accepted:before {
&:extend(.font-icon-class);
content: @fa-var-check-circle;
color: @color-success;
}
&.delegated:before {
&:extend(.font-icon-class);
content: @fa-var-share;
}
&.needs-action:before {
&:extend(.font-icon-class);
content: @fa-var-question-circle;
}
}
.attendee {
&:before {
&:extend(.font-icon-class);
@ -643,4 +647,28 @@ html.touch {
margin-right: .25rem;
}
}
.message {
display: flex;
}
& + .savemode {
margin-top: 1rem;
a.btn {
margin-right: .5rem;
}
}
& > .savemode {
margin-top: .5rem;
label {
margin-right: 1rem;
}
input {
margin-right: .25rem;
}
}
}

View file

@ -304,6 +304,10 @@ html.touch #tasklist {
.attachmentslist li {
margin-right: 1em;
}
.faded {
color: @color-black-shade-text;
}
}
#taskedit-attachment-form {

View file

@ -390,7 +390,7 @@ button.btn.print:before {
padding: .5em 1em;
background-color: @color-black-shade-bg;
button {
button.print {
margin-right: 1rem;
}

View file

@ -166,11 +166,11 @@
<label class="col-sm-4 col-form-label"><roundcube:label name="attachments" /></label>
<div class="task-text col-sm-8"></div>
</div>
<div id="task-created" class="form-group row">
<div id="task-created" class="form-group row faded">
<label class="col-sm-4 col-form-label"><roundcube:label name="tasklist.created" /></label>
<span class="task-text task-created col-sm-8 form-control-plaintext"></span>
</div>
<div id="task-changed" class="form-group row">
<div id="task-changed" class="form-group row faded">
<label class="col-sm-4 col-form-label"><roundcube:label name="tasklist.changed" /></label>
<span class="task-text task-changed col-sm-8 form-control-plaintext"></span>
</div>

View file

@ -102,7 +102,8 @@
<roundcube:object name="plugin.identity_select" id="edit-identities-list" class="col-sm-10 form-control" />
</div>
<h3 id="aria-label-attendeestable" class="voice"><roundcube:label name="tasklist.arialabeleventassignments" /></h3>
<roundcube:object name="plugin.attendees_list" id="edit-attendees-table" class="edit-attendees-table no-img table-sm" coltitle="attendee" aria-labelledby="aria-label-attendeestable" />
<roundcube:object name="plugin.attendees_list" id="edit-attendees-table" class="edit-attendees-table no-img table table-sm"
coltitle="attendee" aria-labelledby="aria-label-attendeestable" />
<roundcube:object name="plugin.attendees_form" id="edit-attendees-form" />
</fieldset>
<!-- attachments list (with upload form) -->

View file

@ -549,7 +549,7 @@ class tasklist_ui
)))
);
$checkbox = new html_checkbox(array('name' => 'attachments', 'id' => 'task-export-attachments', 'value' => 1, 'class' => 'form-check-input'));
$checkbox = new html_checkbox(array('name' => 'attachments', 'id' => 'task-export-attachments', 'value' => 1, 'class' => 'form-check-input pretty-checkbox'));
$html .= html::div('form-section form-group row form-check',
html::label(array('for' => 'task-export-attachments', 'class' => 'col-sm-4 col-form-label'), $this->plugin->gettext('exportattachments'))
. html::div('col-sm-8', $checkbox->show(1))