Commit 38175e2e authored by Carsten Schoenert's avatar Carsten Schoenert

New upstream version 3.4.20+dfsg1

parent 06cd21e1
......@@ -5,6 +5,8 @@ pipeline {
environment {
CHROME_BIN = 'chromium-browser'
}
options { buildDiscarder(logRotator(numToKeepStr: '50')) }
stages {
stage('Test') {
parallel {
......@@ -19,6 +21,11 @@ pipeline {
sh 'make lintci'
junit allowEmptyResults: true, testResults: 'eslint.xml'
}
post {
always {
cleanWs()
}
}
}
stage('Unittest') {
agent {
......@@ -30,6 +37,11 @@ pipeline {
sh 'make jstestci'
junit 'test/js/result/**/unit.xml'
}
post {
always {
cleanWs()
}
}
}
stage('PHP Lint') {
agent {
......@@ -41,6 +53,11 @@ pipeline {
sh 'make phplintci'
junit allowEmptyResults: true, testResults: 'phpmd.xml'
}
post {
always {
cleanWs()
}
}
}
}
}
......@@ -58,6 +75,11 @@ pipeline {
cobertura coberturaReportFile: 'test/js/coverage/cobertura.xml', conditionalCoverageTargets: '70, 0, 0', failUnhealthy: false, failUnstable: false, lineCoverageTargets: '80, 0, 0', maxNumberOfBuilds: 10, methodCoverageTargets: '80, 0, 0'
publishHTML([allowMissing: false, alwaysLinkToLastBuild: true, keepAll: true, reportDir: 'test/js/coverage/report-html', reportFiles: 'index.html', reportName: 'HTML Report', reportTitles: ''])
}
post {
always {
cleanWs()
}
}
}
}
......
......@@ -131,7 +131,16 @@
if(Ext.isDefined(component.menu) && component.splitOnMoreMenu){
var items = component.menu.items.items;
Ext.each(items,function (item) {
menu.add(this.createMenuConfig(item));
var config = this.createMenuConfig(item);
if(item.isXType('menucheckitem')) {
config.xtype = item.xtype;
var store = item.model.store;
if (store.hasFilterApplied) {
config.iconCls = "";
config.checked = true;
}
}
menu.add(config);
},this);
} else {
orig_addComponentToMenu.apply(this, arguments);
......
This diff is collapsed.
......@@ -68,12 +68,6 @@ q:before, q:after {
width: 100%;
}
/* used to see if all css is loaded before we start printing */
/* line 56, ../../scss/external/_print.scss */
#csscheck {
display: none;
}
/* line 3, ../../scss/external/print.calendar.scss */
table {
width: 100%;
......
......@@ -68,12 +68,6 @@ q:before, q:after {
width: 100%;
}
/* used to see if all css is loaded before we start printing */
/* line 56, ../../scss/external/_print.scss */
#csscheck {
display: none;
}
/* line 3, ../../scss/external/print.record.scss */
table {
width: 100%;
......
......@@ -68,12 +68,6 @@ q:before, q:after {
width: 100%;
}
/* used to see if all css is loaded before we start printing */
/* line 56, ../../scss/external/_print.scss */
#csscheck {
display: none;
}
/* line 3, ../../scss/external/print.task.scss */
table {
width: 100%;
......
......@@ -556,3 +556,16 @@ li.x-menu-item-active{
background-position: sprite-position($iconsmap, icon_calendar_appt_accept, $offset-y: 6, $offset-x: 2) !important;
}
}
.x-menu-check-item.k-unread-filter-btn {
.k-hide-img {
display: none !important;
}
.x-menu-item-icon {
background-position: sprite-position($iconsmap, icon_flag_complete, $offset-y: 6, $offset-x: 2) !important;
}
}
.k-selection {
background-color: $light-blue !important;
}
\ No newline at end of file
......@@ -113,6 +113,25 @@
}
}
.x-btn.k-filter-options-btn {
.x-btn-small {
button {
min-width: 0px !important;
}
}
.x-btn-split {
padding-right: 0px;
background-image: none !important;
}
.icon_filter.x-btn-text {
border-right: none !important;
span {
padding-left: 5px;
}
}
}
/* Meeting/Task request buttongroup */
.x-btn-group.zarafa-mr-buttons, .k-tr-buttons {
.x-btn-group-tl,
......@@ -402,6 +421,11 @@
background-position: sprite-position($icons, icon_recurrence, $offset-y: 4px, $offset-x: $padding-medium);
}
/* filter button */
button.icon_filter {
background-position: sprite-position($icons, icon_filter, $offset-y: 0px, $offset-x: 0px);
}
/* invite button */
button.icon_invite_attendees {
background-position: sprite-position($icons, icon_invite_attendees, $offset-y: 4px, $offset-x: $padding-medium);
......
......@@ -51,8 +51,3 @@ q:before,q:after{
.fullwidth {
width: 100%;
}
/* used to see if all css is loaded before we start printing */
#csscheck {
display: none;
}
......@@ -51,8 +51,9 @@ Zarafa.calendar.Actions = {
*/
openCreateAppointmentContent : function(model, config)
{
var record = model.createRecord();
Zarafa.core.data.UIFactory.openCreateRecord(record, config);
model.createRecord(function(record){
Zarafa.core.data.UIFactory.openCreateRecord(record, config);
}.createDelegate(this, [config], true));
},
/**
......@@ -80,9 +81,10 @@ Zarafa.calendar.Actions = {
*/
openCreateMeetingRequestContent : function(model, config)
{
var record = model.createRecord();
record.convertToMeeting();
Zarafa.core.data.UIFactory.openCreateRecord(record, config);
model.createRecord(function(record){
record.convertToMeeting();
Zarafa.core.data.UIFactory.openCreateRecord(record, config);
}.createDelegate(this, [config], true));
},
/**
......
......@@ -247,7 +247,9 @@ Zarafa.calendar.CalendarContext = Ext.extend(Zarafa.core.Context, {
}
break;
case Zarafa.core.data.SharedComponentType['common.contextmenu']:
if (record instanceof Zarafa.core.data.MessageRecord && record.isMessageClass(['IPM.Appointment', 'IPM.OLE.CLASS.{00061055-0000-0000-C000-000000000046}'], true)) {
if (!record) {
bid = 1;
} else if (record instanceof Zarafa.core.data.MessageRecord && record.isMessageClass(['IPM.Appointment', 'IPM.OLE.CLASS.{00061055-0000-0000-C000-000000000046}'], true)) {
bid = 1;
}
break;
......
......@@ -142,19 +142,64 @@ Zarafa.calendar.CalendarContextModel = Ext.extend(Zarafa.core.MultiFolderContext
}
},
/*
* Check if user has enough permissions to create record in given folder.
* A confirmation message will be raised when user don't have enough permissions
* asking to use default folder instead.
* @param {Function} callback The callback function which will be called once the record gets created.
* @param {Zarafa.core.IPMFolder} folder The target folder in which the new record will be created.
* @param {Zarafa.core.DateRange} dateRange The {@link Zarafa.core.DateRange DateRange} object
* @return {Boolean} true if user has enough permissions, false otherwise.
*/
checkCreateRights : function(callback, folder, dateRange)
{
if (folder.get('rights') & Zarafa.core.mapi.Rights.RIGHTS_CREATE) {
return true;
} else {
Zarafa.common.dialogs.MessageBox.addCustomButtons({
width: 400,
title: _('Create in other calendar'),
msg : _('The selected calendar has \"read-only\" permissions. Instead you can create an item in your own calendar.') + '<br><br>' + _('What would you like?'),
icon: Ext.MessageBox.QUESTION,
fn : function(buttonName){
if ( buttonName === 'own' ){
this.createRecord(callback, this.defaultFolder, dateRange);
}
},
customButton: [{
name : 'own',
text: _('Own calendar')
}, {
name : 'cancel',
text: _('Cancel')
}],
scope: this
});
return false;
}
},
/**
* Create a new {@link Zarafa.core.data.IPMRecord IPMRecord} record which is associated to this context.
* this is a base function to create record. each context will overwrite this function to
* create record of that specific context.
* @param {Function} callback The callback function which will be called once the record gets created.
* @param {Zarafa.core.IPMFolder} folder (optional) The target folder in which the new record must be
* created. If this is not provided the default folder will be used.
* @param {Zarafa.core.DateRange} dateRange (optional) The {@link Zarafa.core.DateRange DateRange} object
* that should be used to get start and due dates for the appointment.
* @return {Zarafa.core.data.IPMRecord} record which is associated to this context.
*/
createRecord : function(folder, dateRange)
createRecord : function(callback, folder, dateRange)
{
folder = folder || this.getDefaultFolder();
// check for create permissions
if (!this.checkCreateRights(callback, folder, dateRange)) {
return;
}
var store;
if (folder.existsInFavorites()) {
store = container.getHierarchyStore().getById(folder.get('store_entryid'));
......@@ -200,7 +245,12 @@ Zarafa.calendar.CalendarContextModel = Ext.extend(Zarafa.core.MultiFolderContext
alldayevent : allDay
});
return record;
// call callback if provided, return newly created record otherwise
if (Ext.isDefined(callback)) {
callback.call(this, record);
} else {
return record;
}
},
/**
......
......@@ -794,19 +794,7 @@ Zarafa.calendar.dialogs.AppointmentTab = Ext.extend(Ext.form.FormPanel, {
}
if (contentReset && this.comboCreateIn.isVisible()) {
const model = container.getContextByName('calendar').getModel();
const selectedFolder = model.getFolder(record.get('parent_entryid'));
let folderToSelect;
// Check if folder doesn't belongs to "Deleted Items" / "Junk E-mails" folders or
// user has enough rights.
if (Ext.isDefined(selectedFolder) && (selectedFolder.isInDeletedItems()
|| (!(selectedFolder.get('rights') & Zarafa.core.mapi.Rights.RIGHTS_CREATE)))) {
folderToSelect = model.defaultFolder.get('entryid');
} else {
folderToSelect = record.get('parent_entryid');
}
const folderToSelect = record.get('parent_entryid');
this.comboCreateIn.setValue(folderToSelect);
const folderColor = this.getFolderColor(folderToSelect);
......
......@@ -165,10 +165,7 @@ Zarafa.calendar.ui.CalendarContextMenu = Ext.extend(Zarafa.core.ui.menu.Conditio
text : _('Categories'),
hideOnClick: false,
beforeShow : this.beforeShowNonPhantom,
menu: {
xtype: 'zarafa.categoriescontextmenu',
records: records
}
menu: this.createSubCategories(records)
},{
xtype : 'zarafa.conditionalitem',
iconCls : 'icon_busystatus',
......@@ -181,6 +178,22 @@ Zarafa.calendar.ui.CalendarContextMenu = Ext.extend(Zarafa.core.ui.menu.Conditio
}];
},
/**
* Create the sub context menu items for categories only if records are supplied.
* @param {Zarafa.core.data.IPMRecord[]} records The records on which this menu acts
* @return {Object} The object of Options containing {@link Zarafa.common.categories.ui.CategoriesContextMenu}
* @private
*/
createSubCategories : function(records)
{
if (records) {
return {
xtype: 'zarafa.categoriescontextmenu',
records: records
};
}
},
/**
* Create the Busy status context submenu items
* @return {Zarafa.core.ui.menu.ConditionalItem[]} The list of Busy status context submenu items
......@@ -239,9 +252,11 @@ Zarafa.calendar.ui.CalendarContextMenu = Ext.extend(Zarafa.core.ui.menu.Conditio
beforeShowPhantom : function(item, records)
{
var hasNonPhantoms = false;
for (var i = 0, len = records.length; i < len; i++) {
if (records[i].phantom === false) {
hasNonPhantoms = true;
if (records) {
for (var i = 0, len = records.length; i < len; i++) {
if (records[i].phantom === false) {
hasNonPhantoms = true;
}
}
}
item.setVisible(!hasNonPhantoms);
......@@ -257,12 +272,16 @@ Zarafa.calendar.ui.CalendarContextMenu = Ext.extend(Zarafa.core.ui.menu.Conditio
beforeShowNonPhantom : function(item, records)
{
var hasPhantoms = false;
for (var i = 0, len = records.length; i < len; i++) {
if (records[i].phantom === true) {
hasPhantoms = true;
if (records) {
for (var i = 0, len = records.length; i < len; i++) {
if (records[i].phantom === true) {
hasPhantoms = true;
}
}
item.setVisible(!hasPhantoms);
} else {
item.setVisible(false);
}
item.setVisible(!hasPhantoms);
},
/**
......@@ -275,7 +294,7 @@ Zarafa.calendar.ui.CalendarContextMenu = Ext.extend(Zarafa.core.ui.menu.Conditio
beforeShowOnMeeting : function(item, records)
{
// If user has select more then one record then we should not have to show the menu items.
if(records.length > 1){
if(!records || records.length > 1){
return;
}
......@@ -487,18 +506,38 @@ Zarafa.calendar.ui.CalendarContextMenu = Ext.extend(Zarafa.core.ui.menu.Conditio
*/
onCreate : function(button)
{
if (button.meetingRequest) {
for (var i = 0, len = this.records.length; i < len; i++) {
var record = this.records[i];
if (!this.records) {
var model = this.calendarPanel.model;
var calendarView = this.calendarPanel.getView();
var activeCalendar = calendarView.rangeSelectionModel.calendarView;
var rangeModel = this.calendarPanel.getRangeSelectionModel();
model.createRecord(function(record){
this.openContent(button, [record]);
}.createDelegate(this, [button], true), activeCalendar.getSelectedFolder(), rangeModel.dateRange);
} else {
this.openContent(button, this.records);
}
},
/**
* Helper function to open dialog for new appointment / meeting request.
* @param {Zarafa.core.ui.menu.ConditionalItem} button The selected menuitem
* @param {Zarafa.core.data.MAPIRecord[]} records The records on which this contextmenu gets opened
*/
openContent : function(button, records)
{
if (button.meetingRequest) {
for (var i = 0, len = records.length; i < len; i++) {
var record = records[i];
// Change meeting status only if it is not a meeting, otherwise leave as it is (in order not to overwrite old meeting status)
if (record.get('meeting') === Zarafa.core.mapi.MeetingStatus.NONMEETING) {
record.convertToMeeting();
}
}
Zarafa.calendar.Actions.openMeetingRequestContent(this.records);
Zarafa.calendar.Actions.openMeetingRequestContent(records);
} else {
Zarafa.calendar.Actions.openAppointmentContent(this.records);
Zarafa.calendar.Actions.openAppointmentContent(records);
}
}
});
......
......@@ -588,16 +588,16 @@ Zarafa.calendar.ui.CalendarMultiView = Ext.extend(Zarafa.core.ui.View, {
this.rangeSelectionModel.clearSelections();
this.selectionModel.selectRecord(record, false);
}
this.fireEvent('contextmenu', event, record);
} else {
if (range) {
record = this.model.createRecord(calendar.getSelectedFolder(), range);
this.rangeSelectionModel.set(range, calendar);
this.selectionModel.clearSelections();
}
this.selectionModel.clearSelections();
this.fireEvent('contextmenu', event);
}
this.fireEvent('contextmenu', event, record);
},
/**
......
......@@ -711,14 +711,15 @@ Zarafa.calendar.ui.CalendarPanel = Ext.extend(Ext.Panel, {
onAppointmentCreate : function(multiview, folder, dateRange, text)
{
if (this.fireEvent('beforeappointmentcreate', this, folder, dateRange, text) !== false) {
var record = this.model.createRecord(folder, dateRange);
record.set('subject', text);
this.model.createRecord(function(record){
record.set('subject', text);
this.store.add(record);
record.save();
this.store.add(record);
record.save();
this.fireEvent('appointmentcreate', this, folder, record);
this.fireEvent('appointmentcreate', this, folder, record);
}.createDelegate(this, [folder, text], true), folder, dateRange);
}
},
......
......@@ -384,9 +384,7 @@ Zarafa.calendar.ui.canvas.AppointmentProxy = Ext.extend(Zarafa.calendar.ui.Appoi
*/
onContextMenu : function(event)
{
var model = this.parentView.parentView.model;
var record = model.createRecord(this.parentView.getSelectedFolder(), this.getDateRange());
this.parentView.fireEvent('contextmenu', this.parentView, event, record);
this.parentView.fireEvent('contextmenu', this.parentView, event);
},
/**
......@@ -397,7 +395,9 @@ Zarafa.calendar.ui.canvas.AppointmentProxy = Ext.extend(Zarafa.calendar.ui.Appoi
onDoubleClick : function(event)
{
var model = this.parentView.parentView.model;
var record = model.createRecord(this.parentView.getSelectedFolder(), this.getDateRange());
this.parentView.fireEvent('dblclick', this.parentView, event, record);
model.createRecord(function(record){
this.parentView.fireEvent('dblclick', this.parentView, event, record);
}.createDelegate(this, [event], true), this.parentView.getSelectedFolder(), this.getDateRange());
}
});
......@@ -35,7 +35,10 @@ Zarafa.common.categories.ui.CategoriesContextMenu = Ext.extend(Ext.menu.Menu, {
} else {
this.records = config.records;
}
this.store = this.records[0].getStore();
if(Ext.isDefined(this.records[0])) {
this.store = this.records[0].getStore();
}
Ext.applyIf(config, {
xtype: 'zarafa.categoriescontextmenu',
......
Ext.namespace('Zarafa.common.data');
/**
* @class Zarafa.common.data.Filters
* @extends Zarafa.core.Enum
*
* Enum containing the different filters for the stores.
*
* @singleton
*/
Zarafa.common.data.Filters = Zarafa.core.Enum.create({
/**
* UNREAD which used to filter all unread items from store.
*
* @property
* @type Number
*/
UNREAD : 0
});
......@@ -30,38 +30,12 @@ Zarafa.common.printer.renderers.BaseRenderer = Ext.extend(Object, {
win.document.write(this.generateHTML(component));
win.document.close();
this.postRender(window.document, win.document, component);
this.doPrintOnStylesheetLoad.defer(10, this, [win]);
}
},
/**
* check if style is loaded and do print afterwards
*
* @param {window} win
*/
doPrintOnStylesheetLoad: function(win)
{
if (win) {
// Search for the images, if they are not loaded yet, reschedule
var images = win.document.getElementsByTagName('img');
for (var i = 0, len = images.length; i < len; i++) {
var image = images[i];
if (image.complete !== true || image.src && image.width + image.height === 0 ) {
this.doPrintOnStylesheetLoad.defer(10, this, [win]);
return;
}
}
// Search for the CSS, if it is not available yet, reschedule
var el = win.document.getElementById('csscheck'),
comp = el.currentStyle || win.getComputedStyle(el, null);
if (comp.display !== "none") {
this.doPrintOnStylesheetLoad.defer(10, this, [win]);
return;
}
win.print();
win.close();
// Show print dialog when window has loaded all resources.
win.onload = function(win) {
win.print();
win.close();
}.defer(10, this, [win]);
}
},
......@@ -81,7 +55,6 @@ Zarafa.common.printer.renderers.BaseRenderer = Ext.extend(Object, {
'<title>' + this.getTitle(component) + '</title>\n' +
'</head>\n' +
'<body>\n' +
'<div id="csscheck"></div>\n' +
'<div id="pagemargin">\n' +
this.generateBodyTemplate(component) +
'</div>\n' +
......
......@@ -191,8 +191,6 @@ Zarafa.common.reminder.data.ReminderStore = Ext.extend(Zarafa.core.data.ListModu
if (success !== false) {
var records = data.records;
// @FIXME server sends md5 checksum for this checking, so its better to use that checksum here
var newChecksum = Ext.util.JSON.encode(Ext.pluck(records, 'id'));
// if checksum has been changed that means we should update the store with new data
......
......@@ -61,7 +61,8 @@ Zarafa.common.ui.ContextMainPanelToolbar = Ext.extend(Ext.Toolbar, {
// We add the default buttons
items = items.concat([
'->',
'->',
container.populateInsertionPoint('context.mainpaneltoolbar.item', config.context),
{
xtype: 'zarafa.toolbarbutton',
overflowText : _('Copy/Move'),
......@@ -113,7 +114,6 @@ Zarafa.common.ui.ContextMainPanelToolbar = Ext.extend(Ext.Toolbar, {
this.on('afterlayout', this.resizeSearchField, this, {delay : 2, single : true});
},
/**
* Open the {@link Zarafa.common.dialogs.CopyMoveContentPanel CopyMoveContentPanel} for copying
* or moving the currently selected folders.
......@@ -175,6 +175,25 @@ Zarafa.common.ui.ContextMainPanelToolbar = Ext.extend(Ext.Toolbar, {
var containerWidth = this.el.getStyleSize().width;
var copyButtonWidth = 0;
var deleteButtonWidth = 0;
var filterButtonWidth = 0;
if(Ext.isDefined(this.filterBtn)) {
if(this.filterBtn.xtbHidden) {
filterButtonWidth = this.filterBtn.xtbWidth;
if (containerWidth > this.searchFieldContainer.getWidth() + filterButtonWidth) {
this.layout.unhideItem(this.filterBtn);
// Update the selection of filter split button.
if (!Ext.isEmpty(this.model)) {
if (this.model.getStore().hasFilterApplied) {
this.filterBtn.btnEl.addClass('k-selection');
}
}
this.doLayout();
}
} else {
filterButtonWidth = this.filterBtn.getWidth();
}
}
/*
* Check if copyButton is visible then get width of the same,
......@@ -207,7 +226,7 @@ Zarafa.common.ui.ContextMainPanelToolbar = Ext.extend(Ext.Toolbar, {
}
var extraMargin = 0;
var adjWidth = containerWidth - copyButtonWidth - deleteButtonWidth - extraMargin;