...
 
Commits (8)
......@@ -18,7 +18,7 @@ JSDEPLOY = $(DESTDIR)/client
JSCOMPILER ?= $(JAVA) -jar tools/lib/compiler.jar
JSOPTIONS = --externs client/externs.js \
--compilation_level SIMPLE --warning_level VERBOSE --jscomp_off=es5Strict \
--compilation_level SIMPLE --warning_level VERBOSE --jscomp_off=es5Strict --strict_mode_input=false \
--jscomp_off=globalThis --jscomp_off=misplacedTypeAnnotation --jscomp_off=nonStandardJsDocs \
--jscomp_off=missingProperties --jscomp_off=invalidCasts --jscomp_off=checkTypes \
--jscomp_warning=visibility --jscomp_warning=unknownDefines --jscomp_warning=undefinedVars \
......@@ -152,13 +152,15 @@ $(JSDEPLOY)/resize.js: client/resize.js
cat client/resize.js > $(JSDEPLOY)/resize-debug.js
$(JSCOMPILER) --js $(@:.js=-debug.js) --js_output_file $@
$(JSDEPLOY)/third-party/ux-thirdparty.js: client/third-party/tinymce/TinyMceTextArea.js
$(JSDEPLOY)/third-party/ux-thirdparty.js: $(JSDEPLOY)/third-party/TinyMceTextArea-debug.js client/third-party/tokenizr/tokenizr.min.js
mkdir -p $(JSDEPLOY)/third-party
cat client/third-party/tinymce/TinyMceTextArea.js > $(JSDEPLOY)/third-party/ux-thirdparty-debug.js
$(JSCOMPILER) --js $(@:.js=-debug.js) --js_output_file $@ \
--source_map_location_mapping=$(JSDEPLOY)/third-party/\| \
--output_wrapper="%output%//# sourceMappingURL=$(shell basename $@.map)" \
--create_source_map $@.map $(JSOPTIONS)
# concatenate using cat
cat $^ > $@
$(JSDEPLOY)/third-party/TinyMceTextArea-debug.js: client/third-party/tinymce/TinyMceTextArea.js
mkdir -p $(JSDEPLOY)/third-party
cp $< $@
$(JSCOMPILER) --js $< --js_output_file $@
config:
cp $(DESTDIR)/config.php.dist $(DESTDIR)/config.php
......
......@@ -279,15 +279,21 @@
</zCompile>
<echo message="Compiling: ${thirdparty-file}" />
<zCompile inputFolder="${target-folder}/${thirdparty-folder}" inputFile="${thirdparty-debugfile}" outputFolder="${target-folder}/${thirdparty-folder}" outputFile="${thirdparty-file}" warningLevel="default">
<zCompile inputFolder="${target-folder}/${thirdparty-folder}" inputFile="${thirdparty-debugfile}" outputFolder="${target-folder}/${thirdparty-folder}" outputFile="${thirdparty-file}" warningLevel="QUIET">
<externs>
var Ext = {};
var console = {};
var exports = {};
var module = {};
var define = {};
var global = {};
var require = {};
var Proxy = {};
</externs>
</zCompile>
<echo message="Compiling: ${kopano-file}" />
<zCompile inputFolder="${target-folder}/${kopano-folder}" inputFile="${kopano-debugfile}" outputFolder="${target-folder}/${kopano-folder}" outputFile="${kopano-file}">
<zCompile inputFolder="${target-folder}/${kopano-folder}" inputFile="${kopano-debugfile}" outputFolder="${target-folder}/${kopano-folder}" outputFile="${kopano-file}" checkRegExp="off">
<externs>
var FormData = {};
var Ext = {};
......@@ -310,6 +316,7 @@
var pgettext = function(msgctxt, msgid) {};
var resizeLoginBox = function() {};
var tinymce = {};
var Tokenizr = {};
</externs>
</zCompile>
</target>
......
......@@ -11,6 +11,12 @@ var user = {};
var version = {};
var urlActionData = {};
var console = {};
var Tokenizr = {};
var module;
var define;
var global;
var require;
var proxy;
var _ = function(key, domain) {};
var dgettext = function(domain, msgid) {};
var dngettext = function(domain, msgid, msgid_plural, count) {};
......
......@@ -2,7 +2,7 @@
var checkPerc = /^(100?|\d?\d)?%?$/;
var checkNaturalInteger = /^[1-9]\d*$/i;
// Override regex to allow TLD with max length of 10 characters
var email = /^(\w+)([\-+.\'][\w]+)*@(\w[\-\w]*\.){1,5}([A-Za-z]){2,10}$/;
var email = /^(\w+)([\-+.\']+[\w]+)*@(\w[\-\w]*\.){1,5}([A-Za-z]){2,10}$/;
/**
* @class Ext.form.VTypes
......
This diff is collapsed.
......@@ -2,5 +2,7 @@
"id": "breeze",
"display-name": "Breeze",
"stylesheet": "breeze-icons.css",
"primary-color": "#6d6d70",
"secondary-color": "#19b5f1",
"about": "The Breeze iconset was created by <a target=\"_blank\" href=\"https://www.patreon.com/user?u=10071325\">Andreas Kainz</a>"
}
\ No newline at end of file
......@@ -81,7 +81,6 @@
div {
padding: $padding-medium;
background: $light-blue;
border: 1px solid $grey5;
}
}
......@@ -233,7 +232,8 @@
.k-datepanel,
.k-workpanel,
.k-companypanel {
.k-companypanel,
.k-updatelistpanel {
padding: $padding-medium;
}
......@@ -242,9 +242,11 @@
padding-left: $padding-extra-extra-large;
}
}
.k-updatelistpanel .x-form-item {
padding: $padding-medium;
.k-updatelistpanel {
.x-btn {
padding-top: $padding-medium;
}
}
}
......@@ -391,4 +393,4 @@
border-left: none;
}
}
}
\ No newline at end of file
}
......@@ -110,8 +110,7 @@ $preview-header-collapse-icon-height : 5;
}
.preview-header-recipients .preview-recipient-title,
.preview-header-attachments .preview-attachment-title
{
.preview-header-attachments .preview-attachment-title {
float:left;
}
......@@ -138,14 +137,12 @@ $preview-header-collapse-icon-height : 5;
/* Overflow for recipients / attachments */
.preview-header-recipients .preview-recipient-data,
.preview-header-attachments .preview-attachment-data
{
.preview-header-attachments .preview-attachment-data {
overflow-y: auto;
}
/* Attachments: */
.preview-header-attachmentbox
{
.preview-header-attachmentbox {
line-height:18px;
padding-top:2px;
}
......@@ -158,23 +155,14 @@ $preview-header-collapse-icon-height : 5;
/* Top header infobox */
.preview-header-extrainfobox {
// FIXME: SASS Color
background-color: #D2E0F0;
color: #000000;
padding: 2px 0px;
background-color: $light-blue;
margin-bottom: $padding-small;
padding: $padding-medium $padding-large $padding-medium $padding-large;
}
/* Corrupt message case */
.preview-header-extrainfobox-item-over {
// FIXME: SASS Color
background-color: #FFBD69;
cursor : pointer;
}
.preview-header-extrainfobox-item {
padding: 0px 8px;
// FIXME: SASS Color
color: #15428B;
cursor: pointer;
}
/* Preview header email address */
......@@ -189,15 +177,14 @@ span.zarafa-emailaddress-link:hover {
}
.preview-title-hr {
margin : 2px 0;
margin: 2px 0;
}
.preview-recipient-data {
word-wrap: break-word;
}
.preview-header-attachments .zarafa-attachment-link
{
.preview-header-attachments .zarafa-attachment-link {
// FIXME: sassify
border-radius: 4px;
border: 1px solid #d3d2d2;
......@@ -209,8 +196,7 @@ span.zarafa-emailaddress-link:hover {
cursor: pointer;
}
.preview-header-attachments .zarafa-attachment-link-over
{
.preview-header-attachments .zarafa-attachment-link-over {
// FIXME: sassify
background-color: #ddd;
}
......
Tokenizr in Kopano WebApp
=========================
The tokenizr library can be found at https://github.com/rse/tokenizr
However we made a small adjustment to support unicode matching rules
Until this changed has been merged into the original master branch,
the following branch should be used:
https://github.com/rotous/tokenizr/tree/unicode-support
This diff is collapsed.
......@@ -797,6 +797,9 @@ Ext.apply(Zarafa, {
Zarafa.initializeGlobals();
Zarafa.initializeEnvironment();
// Recolor the icons if necessary
this.recolorIcons();
// Start loading all plugins
Zarafa.fireReady();
......@@ -945,6 +948,67 @@ Ext.apply(Zarafa, {
container.switchContext(plugin);
},
/**
* When an iconset has SVG icons and it has defined the primary-color and/or
* secondary-color properties and the active theme has defined the
* icons-primary-color and/or icons-secondary-color property this function
* will rewrite the css rules of the iconset to update the colors of the icons.
*/
recolorIcons : function()
{
// Get the properties defined by the active iconset
var serverConfig = container.getServerConfig();
var iconsets = serverConfig.getIconsets();
var activeIconsetName = serverConfig.getActiveIconset();
var activeIconset = iconsets[activeIconsetName];
// If the iconset did not define a primary or secondary color, we cannot
// redefine the colors, so return without doing anything
if ( !activeIconset['primary-color'] && !activeIconset['secondary-color'] ) {
return;
}
// Get the primary and secondary icon color defined in the active theme
// (themes can override the colors of iconsets that allow recoloring)
var themeIconsPrimaryColor = serverConfig.getPrimaryIconColor();
var themeIconsSecondaryColor = serverConfig.getSecondaryIconColor();
// If the active theme did not define a new primary or secondary color
// for the icons there is nothing to do, so return
if ( !themeIconsPrimaryColor && !themeIconsSecondaryColor ) {
return;
}
// Get the stylesheet element that contains the icons as background images
// and check all rules in it for SVG icons we can recolor
var sheet = document.getElementById('kopano-iconset-stylesheet');
for ( var i=0; i<sheet.sheet.cssRules.length; i++ ) {
var rule = sheet.sheet.cssRules[i];
// Check the rule to see if it contains an SVG background image
// (we can only recolor SVG icons)
var matches = (/url\("data:image\/svg\+xml;base64,(.+?)"\)/).exec(rule.cssText);
if ( matches !== null ) {
// base64 decode the SVG image
var svg = atob(matches[1]);
// Simply replace the color codes
var svgRecolored = svg.replace(activeIconset['primary-color'], themeIconsPrimaryColor).replace(activeIconset['secondary-color'], themeIconsSecondaryColor);
// If we changed anything, replace the CSS rule to use the base64 encoded SVG
// with the new color(s)
if ( svg !== svgRecolored ) {
var cssText = rule.cssText.replace(
/url\("data:image\/svg\+xml;base64,(.+)"\)/,
'url("data:image/svg+xml;base64,' + btoa(svgRecolored) + '")'
);
sheet.sheet.deleteRule(i);
sheet.sheet.insertRule(cssText, i);
}
}
}
},
/**
* Check if user is out of office
* If so, ask them if they want to switch OOF off
......
This diff is collapsed.
......@@ -93,7 +93,7 @@ Zarafa.advancesearch.dialogs.SearchToolBoxPanel = Ext.extend(Ext.Panel, {
autoLoad: true,
data: Zarafa.advancesearch.data.DateRangeFields
};
Ext.applyIf(config, {
xtype : 'zarafa.searchtoolboxpanel',
title: _('Search tools'),
......@@ -121,9 +121,13 @@ Zarafa.advancesearch.dialogs.SearchToolBoxPanel = Ext.extend(Ext.Panel, {
this.createCategoryFilterFieldset(dateRangeStore),
this.createFavoritesContainer(config)
]
}]
}],
listeners: {
afterrender: this.onAfterRender,
scope: this
}
});
this.addEvents(
/**
* @event afterupdaterestriction fired after the {@link #searchCriteria} gets updated by the
......@@ -136,6 +140,47 @@ Zarafa.advancesearch.dialogs.SearchToolBoxPanel = Ext.extend(Ext.Panel, {
Zarafa.advancesearch.dialogs.SearchToolBoxPanel.superclass.constructor.call(this, config);
},
/**
* Event handler for the render event of the SearchToolBoxPanel. Will add an event listener to the
* input element of the {@link Zarafa.common.searchfield.ui.SearchTextField}
*/
onAfterRender : function()
{
var searchTextField = this.ownerCt.searchToolbar.contextMainPanelToolbar.searchFieldContainer.searchTextField;
// Because the input event is not relayed by the Ext.form.TextField (like e.g. keyup) we must listen
// to the input element itself. We can only add the listener once it has been rendered, hence the
// double mon()
this.mon(searchTextField, 'render', function() {
this.mon(searchTextField.getEl(), 'input', this.onSearchTextFieldChange, this);
// Call the listener also upon rendering of the searchTextField, since we might need to disable the
// search fields of the toolbox
this.onSearchTextFieldChange();
}, this, {single: true});
},
/**
* Event handler for the input event of the input of the {@link Zarafa.common.searchfield.ui.SearchTextField}
* Will disable the search field panels when the search query is a KQL query, or enable them otherwise
* @param {Zarafa.common.searchfield.ui.SearchTextField} searchTextField The text field where the
* search queries are entered.
*/
onSearchTextFieldChange : function()
{
var searchTextField = this.ownerCt.searchToolbar.contextMainPanelToolbar.searchFieldContainer.searchTextField;
var query = searchTextField.getValue();
var isKqlQuery = Zarafa.advancesearch.KQLParser.isKqlQuery(query);
if ( isKqlQuery ) {
this.searchInFieldset.disable();
this.categoryFilterFieldSet.disable();
} else {
this.searchInFieldset.enable();
this.categoryFilterFieldSet.enable();
}
},
/**
* Creates the folders fieldset for search tool box of form panel.
* @return {Object} config object for creating {@link Ext.form.FieldSet FieldSet}.
......@@ -330,6 +375,7 @@ Zarafa.advancesearch.dialogs.SearchToolBoxPanel = Ext.extend(Ext.Panel, {
cls: 'k-category-filter',
title: _('Filter category..'),
autoHeight: true,
ref: '../categoryFilterFieldSet',
items: [{
xtype: 'button',
iconCls: 'icon_category_add',
......@@ -385,6 +431,7 @@ Zarafa.advancesearch.dialogs.SearchToolBoxPanel = Ext.extend(Ext.Panel, {
width : 160,
border : false,
title: _('Search..'),
ref : '../searchInFieldset',
items : [{
xtype : 'checkboxgroup',
columns : 1,
......@@ -828,6 +875,7 @@ Zarafa.advancesearch.dialogs.SearchToolBoxPanel = Ext.extend(Ext.Panel, {
Zarafa.advancesearch.Actions.openCreateSearchFolderContentPanel(this.model, config);
},
/**
* Function will be used to create search restriction based on value entered in
* search textfield and {@link Zarafa.common.search.dialogs.SearchToolBoxPanel SearchToolBox}.
......@@ -844,8 +892,15 @@ Zarafa.advancesearch.dialogs.SearchToolBoxPanel = Ext.extend(Ext.Panel, {
return [];
}
var tokens = Zarafa.advancesearch.KQLParser.tokenize(textFieldValue);
if ( tokens ) {
var tokenRes = Zarafa.advancesearch.KQLParser.createTokenRestriction(tokens);
var andRes = [tokenRes];
} else {
andRes = [];
}
var finalRes = [];
var andRes = [];
var orResDate = [];
var orResSearchField = [];
var orResMessageClass = [];
......@@ -853,17 +908,19 @@ Zarafa.advancesearch.dialogs.SearchToolBoxPanel = Ext.extend(Ext.Panel, {
var orFilters = [];
Ext.iterate(this.searchCriteria, function(key, values) {
// search field restriction
if(key === 'search_fields') {
Ext.each(values, function(value){
orResSearchField.push(
Zarafa.core.data.RestrictionFactory.dataResContent(
value,
Zarafa.core.mapi.Restrictions.FL_SUBSTRING | Zarafa.core.mapi.Restrictions.FL_IGNORECASE,
textFieldValue
)
);
}, this);
if ( !tokens ) {
// search field restriction
if(key === 'search_fields') {
Ext.each(values, function(value){
orResSearchField.push(
Zarafa.core.data.RestrictionFactory.dataResContent(
value,
Zarafa.core.mapi.Restrictions.FL_SUBSTRING | Zarafa.core.mapi.Restrictions.FL_IGNORECASE,
textFieldValue
)
);
}, this);
}
}
if (key === 'extra_fields') {
......@@ -925,6 +982,7 @@ Zarafa.advancesearch.dialogs.SearchToolBoxPanel = Ext.extend(Ext.Panel, {
]);
}
}
// message class restriction
if(key === 'message_class' && !Ext.isEmpty(values)) {
Ext.each(values, function(value){
......@@ -939,7 +997,7 @@ Zarafa.advancesearch.dialogs.SearchToolBoxPanel = Ext.extend(Ext.Panel, {
}
// category restriction
if (key === 'categories' && !Ext.isEmpty(values)) {
if (!tokens && key === 'categories' && !Ext.isEmpty(values)) {
Ext.each(values, function (value) {
andResCategory.push(
Zarafa.core.data.RestrictionFactory.dataResContent(
......@@ -976,9 +1034,11 @@ Zarafa.advancesearch.dialogs.SearchToolBoxPanel = Ext.extend(Ext.Panel, {
if(!Ext.isEmpty(orResDate)) {
var andResDateSearchField = [];
andResDateSearchField.push(orResDate);
andResDateSearchField.push(Zarafa.core.data.RestrictionFactory.createResOr(orResSearchField));
if ( orResSearchField.length ) {
andResDateSearchField.push(Zarafa.core.data.RestrictionFactory.createResOr(orResSearchField));
}
andRes.push(Zarafa.core.data.RestrictionFactory.createResAnd(andResDateSearchField));
} else {
} else if ( orResSearchField.length ) {
/**
* If date information is not present in search criteria then create search restriction
* something like this.
......
......@@ -404,5 +404,45 @@ Zarafa.calendar.Actions = {
}
}, config.scope);
},
/**
* Converts record to an appointment and calls {@link Zarafa.core.data.UIFactory.openCreateRecord}
* to open the newly created appointment as editable record. The original record isn't removed.
*
* @param {Zarafa.core.data.IPMRecord} records The record which will be converted to an appointment
* @param {Zarafa.calendar.CalendarContextModel} model Used to create a new appointment record
*/
createAppointmentFromMail : function(records, model)
{
var record;
if (Array.isArray(records) && !Ext.isEmpty(records)) {
record = records[0];
} else {
return;
}
if (record.isOpened()) {
this.openHandler(record.getStore(), record, model);
} else {
// If record is not opened, then we need to reopen it to get the body. (For example when the selected records store reloads)
record.getStore().on('open', this.openHandler.createDelegate(this, [model], 2), this, {single : true});
record.open();
}
},
/**
* Handler for {@link Zarafa.core.data.IPMStore store} open event. Converts the opened record
* to an appointment and opens it as editable record.
*
* @param {Zarafa.core.data.IPMStore} store The store of the record.
* @param {Zarafa.core.data.IPMRecord} record The record which will be converted to an appointment
* @param {Zarafa.calendar.CalendarContextModel} model Used to create a new appointment record
*/
openHandler: function(store, record, model)
{
var newAppointmentRecord = record.convertToAppointment(model.getDefaultFolder());
Zarafa.core.data.UIFactory.openCreateRecord(newAppointmentRecord);
}
};
......@@ -73,6 +73,9 @@ Zarafa.calendar.CalendarContext = Ext.extend(Zarafa.core.Context, {
// The control will be shown when the user selects the calendar context from the button panel.
this.registerInsertionPoint('navigation.center', this.createCalendarNavigationPanel, this);
// Adds convert mail to appointment contextmenu item in the mail contextmenu.
this.registerInsertionPoint('context.mail.contextmenu.topoptions', this.convertToAppointment, this);
// Register the calendar category for the settings
this.registerInsertionPoint('context.settings.categories', this.createSettingCategories, this);
......@@ -675,6 +678,53 @@ Zarafa.calendar.CalendarContext = Ext.extend(Zarafa.core.Context, {
context: this.getName(),
id: 'mainmenu-button-calendar'
};
},
/**
* Adds a new contextmenu item in the mail context, which converts an email to an appointment
* @return {Zarafa.core.ui.menu.ConditionalItem} The Action context menu item
* @private
*/
convertToAppointment : function()
{
return {
xtype: 'zarafa.conditionalitem',
text : _('Create Appointment'),
iconCls : 'icon_new_appointment',
hidden: true,
handler: this.onContextItemCreateAppointment,
beforeShow: this.onBeforeShowCreateAppointment,
scope: this
};
},
/**
* Event Handler triggered when {@link #convertToAppointment convert to
* appointment} context menu item is clicked.
*
* @param {Zarafa.core.ui.menu.ConditionalItem} item context menu item
* @private
*/
onContextItemCreateAppointment : function(menuItem)
{
Zarafa.calendar.Actions.createAppointmentFromMail(menuItem.getRecords(), this.getModel());
},
/**
* onBeforeShow handler which disables showing the convert to appointment menuitem
* when a single item is selected and it's a mail item.
*
* @param {Zarafa.core.ui.menu.ConditionalItem} item context menu item
* @private
*/
onBeforeShowCreateAppointment : function(menuItem)
{
var records = menuItem.getRecords();
if (Array.isArray(records) && records.length === 1) {
menuItem.setVisible(records[0].isMessageClass('IPM.Note'));
} else {
menuItem.setVisible(false);
}
}
});
......
......@@ -34,7 +34,6 @@ Zarafa.calendar.ui.MeetingRequestButtons = Ext.extend(Ext.ButtonGroup, {
cls: 'zarafa-mr-buttons',
items: [
this.getRemoveFromCalendarButton(),
this.getNotCurrentButton(),
this.getNoResponseRequiredButton(),
this.getAcceptButton(),
this.getTentativeButton(),
......@@ -112,9 +111,6 @@ Zarafa.calendar.ui.MeetingRequestButtons = Ext.extend(Ext.ButtonGroup, {
// from the calendar.
this.removeFromCalendarButton.setVisible(isMeetingCanceled && !isSubMessage && !apptNotFound);
// When the meeting request is outdated, we can show the non-current button
this.nonCurrentButton.setVisible(isMeetingRequest && !isSubMessage && isMeetingOutOfDate);
// When this meeting is current, but the user did send this meeting request to himself,
// then the user doesn't need to respond.
this.noResponseButton.setVisible(isMeetingRequest && !isSubMessage && senderIsReceiver && !isMeetingOutOfDate);
......@@ -138,11 +134,9 @@ Zarafa.calendar.ui.MeetingRequestButtons = Ext.extend(Ext.ButtonGroup, {
this.calendarButton.setVisible((isMeetingRequest || isMeetingResponse) && !isSubMessage && !apptNotFound);
// Determine the action button
if ( this.acceptButton.isVisible() ){
this.calendarButton.getEl().removeClass('zarafa-action');
} else if ( this.nonCurrentButton.isVisible() ){
if (this.acceptButton.isVisible()) {
this.calendarButton.getEl().removeClass('zarafa-action');
} else if ( this.calendarButton.isVisible() ){
} else if (this.calendarButton.isVisible()) {
this.calendarButton.getEl().addClass('zarafa-action');
}
......@@ -180,27 +174,6 @@ Zarafa.calendar.ui.MeetingRequestButtons = Ext.extend(Ext.ButtonGroup, {
};
},
/**
* @return {Ext.Button} element config which should be
* added in the {@link Ext.Toolbar Toolbar}.
* @private
*/
getNotCurrentButton : function()
{
return {
xtype : 'button',
ref : 'nonCurrentButton',
text : _('Not Current'),
tooltip: {
title: _('Not Current'),
text: _('Meeting Request is out of date')
},
cls: 'tb-calendar-btn-not-current zarafa-action',
handler : this.onNotCurrent,
scope: this
};
},
/**
* @return {Ext.Button} element config which should be
* added in the {@link Ext.Toolbar Toolbar}.
......@@ -374,25 +347,6 @@ Zarafa.calendar.ui.MeetingRequestButtons = Ext.extend(Ext.ButtonGroup, {
};
},
/**
* Function sends request to remove outdated Meeting Request mails.
* @param {Ext.Button} button button object.
* @param {EventObject} eventObject The click event object.
* @private
*/
onNotCurrent : function(button, eventObject)
{
Ext.MessageBox.show({
title: _('Kopano WebApp'),
msg : _('This meeting request is out-of-date and will now be deleted.'),
icon: Ext.MessageBox.WARNING,
record: this.record,
fn: this.removeRecordOnOk,
scope: this,
buttons: Ext.MessageBox.OKCANCEL
});
},
/**
* Function sends request to remove Meeting Request mails which invites
* the organizer himself in the Meeting Request.
......
......@@ -52,6 +52,13 @@ Zarafa.common.freebusy.ui.FreebusyContextMenu = Ext.extend(Zarafa.core.ui.menu.C
hidden : !resolved,
handler: this.openDetailsContent,
scope: this
},{
xtype: 'zarafa.conditionalitem',
text: _('Copy email address'),
iconCls : 'icon_copy',
hidden : !resolved,
handler: this.copyEmail,
scope: this
},'-',{
xtype: 'zarafa.conditionalitem',
text: _('Required Attendee'),
......@@ -116,6 +123,15 @@ Zarafa.common.freebusy.ui.FreebusyContextMenu = Ext.extend(Zarafa.core.ui.menu.C
onRecipientTypeChange: function(item)
{
this.records.set('recipient_type', item.recipientType);
},
/**
* Handler for the "Copy email address" option. This will
* copy email address of the resolved recipient.
*/
copyEmail : function ()
{
Zarafa.common.Actions.copyEmailAddress(this.records);
}
});
......
......@@ -53,14 +53,14 @@ Zarafa.common.recipientfield.ui.RecipientContextMenu = Ext.extend(Zarafa.core.ui
scope: this
},{
xtype: 'zarafa.conditionalitem',
text: _('Copy e-mail address'),
text: _('Copy email address'),
iconCls : 'icon_copy',
hidden : !resolved,
handler: this.copyEmail,
scope: this
},{
xtype: 'zarafa.conditionalitem',
text: _('Send e-mail'),
text: _('Send email'),
iconCls : 'icon_new_email',
handler: this.onEmailRecipient,
scope: this
......
......@@ -7,7 +7,7 @@ Ext.namespace('Zarafa.common.recipientfield.ui');
*
* A {@link Ext.dd.DropZone DropZone} installed on a {@link Zarafa.common.recipientfield.ui.RecipientField RecipientField}
* Ensures cooperation between different RecipientFields' drag and drop zones in order to enable the dragging
* of recipients e.g. from the TO to the CC field of an e-mail.
* of recipients e.g. from the TO to the CC field of an email.
*/
Zarafa.common.recipientfield.ui.RecipientDropZone = Ext.extend(Zarafa.common.ui.BoxFieldDropZone, {
/**
......
......@@ -41,6 +41,24 @@ Zarafa.common.reminder.data.ReminderStore = Ext.extend(Zarafa.core.data.ListModu
*/
showReminderDialog : true,
/**
* The object with the configuration for the {@link Ext.TaskMgr TaskMgr} to start the polling for reminders.
* @property
* @type Object
*/
pollTask : null,
/**
* The notifier plugin that is used to show 'error.json' notifications. If the {#link load loading} of reminders
* is failing because the backend produces an error, we will show the notification once using the originally
* registered notification plugin, and after that we will move the noficiations to the console to not bother the
* user with the same message notification over and over again. Once the backend returns valid responses again
* we will restore the original notifier plugin.
* @property
* @type Zarafa.core.ui.notifier.NotifyPlugin
*/
originalErrorNotifier : undefined,
/**
* @constructor
* @param {Object} config Configuration object
......@@ -104,7 +122,7 @@ Zarafa.common.reminder.data.ReminderStore = Ext.extend(Zarafa.core.data.ListModu
/**
* Event handler will be called when an error/exception is occured at server side,
* and error is returned. And interval will be cleared to avoid more errors.
* and error is returned. The notification method will be changed to avoid more errors.
* @param {Zarafa.core.data.MAPIProxy} proxy object that received the error
* and which fired exception event.
* @param {String} type 'request' if an invalid response from server recieved,
......@@ -117,9 +135,18 @@ Zarafa.common.reminder.data.ReminderStore = Ext.extend(Zarafa.core.data.ListModu
onError : function(proxy, type, action, options, response, args)
{
// if any error occurs in getting reminders then we don't need to nag users by displaying error message
// every time so we will show the error message once and clear the timer, so no more requests for reminder will be sent
if(action === Ext.data.Api.actions.read) {
this.clearReminderInterval();
// every time so we will show the error message once and then use the console notifier for subsequent
// messages
if(action === Ext.data.Api.actions.read && !this.originalErrorNotifier) {
// Store the original notifier so we can restore it later
this.originalErrorNotifier = container.getSettingsModel().get('zarafa/v1/main/notifier/error/value');
container.getSettingsModel().set('zarafa/v1/main/notifier/error/value', 'console');
// Restore the original notifier when everything works again
this.on('load', function() {
container.getSettingsModel().set('zarafa/v1/main/notifier/error/value', this.originalErrorNotifier);
this.originalErrorNotifier = undefined;
}, this, {single: true});
}
// clear the checksum, after getting error we should always show the reminder dialog even if no reminders are changed
......@@ -128,19 +155,18 @@ Zarafa.common.reminder.data.ReminderStore = Ext.extend(Zarafa.core.data.ListModu
/**
* Initialize remider requests to the server. Listen to the aftersend event in the
* {@link Zarafa.core.Request Request} object to reset the counter everytime the clients sends a
* request to the server.
* Initialize reminder requests to the server by {@link Ext.TaskMgr.start starting} a task.
*/
initializeReminderInterval : function()
{
var interval = container.getSettingsModel().get('zarafa/v1/main/reminder/polling_interval');
this.pollTask = {
run: this.sendReminderRequest,
scope: this,
interval: interval * 1000
};
// Fire reminder request automatically at specific interval
if (Ext.isNumber(interval) && interval > 0) {
this.on('load', this.sendReminderRequest, this, { buffer : interval * 1000});
this.sendReminderRequest.defer(interval * 1000, this);
}
Ext.TaskMgr.start(this.pollTask);
},
/**
......@@ -171,7 +197,7 @@ Zarafa.common.reminder.data.ReminderStore = Ext.extend(Zarafa.core.data.ListModu
*/
clearReminderInterval : function()
{
this.un('load', this.sendReminderRequest, this);
Ext.TaskMgr.stop(this.pollTask);
},
/**
......
......@@ -325,7 +325,7 @@ Zarafa.common.ui.messagepanel.MessageBody = Ext.extend(Ext.Container, {
anchorNode.setAttribute('href', link);
anchorNode.setAttribute('target', '_blank');
}else if(parts[i].search(this.emailPattern) != -1){
// Create a new anchor-node for making an e-mail address clickable.
// Create a new anchor-node for making an email address clickable.
var anchorNode = Ext.DomHelper.append(containerNode, {tag: 'a', html: parts[i]});
var link = parts[i];
if(link.indexOf('mailto:') !== 0){
......
......@@ -52,7 +52,7 @@ Zarafa.contact.dialogs.DistlistExternalMemberContentPanel = Ext.extend(Zarafa.co
},
/**
* Create the form in which the new e-mail address info can be fetch
* Create the form in which the new email address info can be fetch
* @return {Object} Configuration object for the form
*/
createFormItems : function()
......
......@@ -18,7 +18,7 @@ Ext.namespace('Zarafa.core.data');
*
* An extension to the {@link Ext.data.Record Record} that adds the open() method for loading
* the 'full' contents of a MAPI item. The list modules on the server side only return partial records,
* omitting, for example, the body of e-mail messages. The open() method can be used to retrieve
* omitting, for example, the body of email messages. The open() method can be used to retrieve
* these fields.
*
*/
......
......@@ -102,13 +102,36 @@ Zarafa.core.data.MessageRecord = Ext.extend(Zarafa.core.data.IPMRecord, {
* @return {Zarafa.core.data.IPMRecord} record The newly created task.
*/
convertToTask : function(folder)
{
return this.convertRecord(folder, 'IPM.Task');
},
/**
* Convert a mail record to an appointment record by using the mail's
* @param {Zarafa.core.IPMFolder} folder The target folder in which the new record must be
* created.
* @return {Zarafa.core.data.IPMRecord} record The newly created appointment.
*/
convertToAppointment : function(folder)
{
return this.convertRecord(folder, 'IPM.Appointment');
},
/**
* Convert a mail record to a record with the provided messageClass
* @param {Zarafa.core.IPMFolder} folder The target folder in which the new record must be
* created.
* @param {String} messageClass the messageClass of the new item.
* @return {Zarafa.core.data.IPMRecord} record The newly created appointment.
* @private
*/
convertRecord : function(folder, messageClass)
{
var defaultStore = folder.getMAPIStore();
var taskRecord = Zarafa.core.data.RecordFactory.createRecordObjectByMessageClass('IPM.Task', {
var newRecord = Zarafa.core.data.RecordFactory.createRecordObjectByMessageClass(messageClass, {
store_entryid : folder.get('store_entryid'),
parent_entryid : folder.get('entryid'),
icon_index : Zarafa.core.mapi.IconIndex['task'],
subject : this.get('subject'),
body : this.getBody(false),
importance : this.get('importance'),
......@@ -116,21 +139,24 @@ Zarafa.core.data.MessageRecord = Ext.extend(Zarafa.core.data.IPMRecord, {
owner : defaultStore.isPublicStore() ? container.getUser().getFullName() : defaultStore.get('mailbox_owner_name')
});
// Set icon based on messageClass
newRecord.set('icon_index', Zarafa.core.mapi.IconIndex[Zarafa.common.ui.IconClass.getIconClassFromMessageClass(newRecord)]);
/**
* By copying the reference to the original mail,
* the server is able to add attachments in to the task.
* the server is able to add attachments in to the appointment.
*/
taskRecord.addMessageAction('source_entryid', this.get('entryid'));
taskRecord.addMessageAction('source_store_entryid', this.get('store_entryid'));
newRecord.addMessageAction('source_entryid', this.get('entryid'));
newRecord.addMessageAction('source_store_entryid', this.get('store_entryid'));
// Initialize the taskRecord with attachments
var store = taskRecord.getAttachmentStore();
// Initialize the appointmentRecord with attachments
var store = newRecord.getAttachmentStore();
var origStore = this.getAttachmentStore();
origStore.each(function (attach) {
store.add(attach.copy());
}, this);
return taskRecord;
return newRecord;
},
/**
......
......@@ -84,6 +84,14 @@ Zarafa.core.data.ServerConfig = Ext.extend(Object, {
return this.meta.always_enabled_plugins || '';
},
/**
* @return {Boolean} True if the What's New dialog is disabled
*/
isWhatsNewDialogDisabled : function()
{
return this.meta.disable_whats_new_dialog === true;
},
/**
* @return {Boolean} True if Advanced Settings are enabled
*/
......@@ -196,6 +204,24 @@ Zarafa.core.data.ServerConfig = Ext.extend(Object, {
return this.meta.iconsets;
},
/**
* @return {String|Boolean} The primary color for SVG icons if defined by the active theme,
* or false otherwise
*/
getPrimaryIconColor : function()
{
return this.meta.icons_primary_color;
},
/**
* @return {String|Boolean} The secondary color for SVG icons if defined by the active theme,
* or false otherwise
*/
getSecondaryIconColor : function()
{
return this.meta.icons_secondary_color;
},
/**
* @return {Object} The about texts of iconsets
*/
......
......@@ -85,10 +85,13 @@ Zarafa.core.ui.MainTabBar = Ext.extend(Ext.Toolbar, {
Zarafa.common.Actions.openReminderContent(store.getRange());
},
listeners : {
render : function() {
afterRender : function(reminderBtn) {
var store = container.getReminderStore();
store.showReminderDialog = false;
store.load();
var recordLength = store.getRange().length;
reminderBtn.getEl().setStyle('backgroundImage', 'url(\'' + Zarafa.common.ui.IconClass.getReminderSvgIcon( recordLength ) + '\')');
var noReminder = recordLength === 0;
reminderBtn.setDisabled(noReminder);
reminderBtn.setTooltip(noReminder? _('There are no reminders') : '');
},
scope : this
},
......
......@@ -197,11 +197,14 @@ Zarafa.hierarchy.ui.TreeSorter = Ext.extend(Ext.tree.TreeSorter, {
// Folders that have the same type will now be sorted based on the passed property
// When sorting on display name, we will use the 'fully qualified display name', so
// we will use 'Calendar of Hank Bla' instead of just 'Calendar' to sort.
var v1 = property = 'display_name' && record1.getFullyQualifiedDisplayName ? record1.getFullyQualifiedDisplayName() : record1.get(property);
var v2 = property = 'display_name' && record2.getFullyQualifiedDisplayName ? record2.getFullyQualifiedDisplayName() : record2.get(property);
// For case insensitive sorting, convert to lowercase, this will correctly position
// folders which start with '_' to be sorted first (when converting to uppercase, those
// folders are otherwise sorted last.
var v1 = record1.get(property);
var v2 = record2.get(property);
if (!caseSensitive) {
v1 = !Ext.isEmpty(v1) ? v1.toLowerCase() : v1;
v2 = !Ext.isEmpty(v2) ? v2.toLowerCase() : v2;
......
......@@ -585,11 +585,11 @@ Zarafa.mail.MailContext = Ext.extend(Zarafa.core.Context, {
var defaultItems = [{
xtype: 'zarafa.conditionalitem',
id: 'zarafa-maintoolbar-print-singlemail',
overflowText: _('Print single e-mail'),
overflowText: _('Print single email'),
iconCls: 'icon_print',
tooltip : _('Print selected email') + ' (Ctrl + P)',
plugins : 'zarafa.menuitemtooltipplugin',
text: _('Print single e-mail'),
text: _('Print single email'),
hideOnDisabled: false,
singleSelectOnly: true,
handler: this.onPrintSingle,
......
......@@ -76,7 +76,7 @@ Zarafa.mail.ui.ExportAsContextMenu = Ext.extend(Zarafa.core.ui.menu.ConditionalM
/**
* Event handler which is called when the user selects the 'Download as files'
* item in the context menu. This will request to download selected message
* as file (RFC822-formatted e-mail stream) with eml extension.
* as file (RFC822-formatted email stream) with eml extension.
* @private
*/
onContextItemEml: function ()
......@@ -87,7 +87,7 @@ Zarafa.mail.ui.ExportAsContextMenu = Ext.extend(Zarafa.core.ui.menu.ConditionalM
/**
* Event handler which is called when the user selects the 'Download as ZIP'
* item in the context menu. This will request to download selected message
* as file (RFC822-formatted e-mail stream) with eml extension included in a ZIP archive.
* as file (RFC822-formatted email stream) with eml extension included in a ZIP archive.
* @private
*/
onContextItemEmlZip: function ()
......
......@@ -77,7 +77,7 @@ Zarafa.settings.data.SettingsDefaultValue = function(){
/**
* zarafa/v1/main/default_font
* Default font for writing e-mail
* Default font for writing email
* @property
* @type String
*/
......@@ -85,7 +85,7 @@ Zarafa.settings.data.SettingsDefaultValue = function(){
/**
* zarafa/v1/main/default_font_size
* Default font size for writing e-mail
* Default font size for writing email
* possible values are {@link Zarafa.common.ui.htmleditor.FontSize#fontSizes}
* @property
* @type Number
......
......@@ -195,6 +195,11 @@ Zarafa.settings.ui.SettingsAccountWidget = Ext.extend(Zarafa.settings.ui.Setting
scope : this
}
});
// Insertion point at the end of the account information widget
config.items.push(
container.populateInsertionPoint('settings.account.last')
);
Zarafa.settings.ui.SettingsAccountWidget.superclass.constructor.call(this, config);
},
......
......@@ -76,7 +76,9 @@ Zarafa.settings.ui.SettingsDisplayWidget = Ext.extend(Zarafa.settings.ui.Setting
change : this.onFieldChange,
scope : this
}
}]
},
// Insertion point at the end of the display widget
container.populateInsertionPoint('settings.display.last')]
});
Zarafa.settings.ui.SettingsDisplayWidget.superclass.constructor.call(this, config);
......
......@@ -162,16 +162,16 @@ Zarafa.task.dialogs.TaskDetailTab = Ext.extend(Ext.form.FormPanel, {
*/
createCompanyPanel : function()
{
return{
layout : 'form',
return {
layout: 'form',
ref: 'companyPanel',
cls: 'k-companypanel',
items : [{
xtype : 'textfield',
fieldLabel:_('Companies'),
anchor : '100%',
name : 'companies',
listeners :{
items: [{
xtype: 'textfield',
fieldLabel: _('Companies'),
anchor: '100%',
name: 'companies',
listeners: {
'change' : this.onPropertyChange,
scope : this
}
......@@ -187,26 +187,24 @@ Zarafa.task.dialogs.TaskDetailTab = Ext.extend(Ext.form.FormPanel, {
*/
createUpdateListPanel : function()
{
return{
layout : 'form',
return {
layout: 'form',
cls: 'k-updatelistpanel',
border : false,
items : [{
xtype : 'textfield',
items: [{
xtype: 'textfield',
fieldLabel:_('Update List'),
labelAlign: 'left',
ref : '../updateList',
anchor : '100%',
readOnly : true,
name : 'updatelist'
ref: '../updateList',
anchor: '100%',
readOnly: true,
name: 'updatelist'
},{
xtype : 'button',
xtype: 'button',
width: 150,
ref : '../createUnassignedCopy',
handler : this.onCreateUnassignedCopy,
text : _('Create Unassigned Copy'),
name : 'create_unassigned_copy',
scope : this
ref: '../createUnassignedCopy',
handler: this.onCreateUnassignedCopy,
text: _('Create Unassigned Copy'),
name: 'create_unassigned_copy',
scope: this
}]
};
},
......
......@@ -8,10 +8,16 @@ Ext.namespace('Zarafa.whatsnew');
Zarafa.whatsnew.Actions = {
/**
* Opens the "What's New" dialog when information on new features is available
* and the user has not chosen to not show the dialog again.
* and the admin or user has not chosen to not show the dialog.
*/
openWhatsNewDialog : function()
{
// Don't show new features if the admin has disabled the dialog
var serverConfig = container.getServerConfig();
if ( serverConfig.isWhatsNewDialogDisabled() ) {
return;
}
// Don't show new features if the user once checked the "Don't show me new features again." checkbox
var sm = container.getSettingsModel();
if ( sm.get('zarafa/v1/main/new_features_dialog/show') === false ){
......
......@@ -114,13 +114,13 @@ Zarafa.whatsnew.ui.WhatsNewWindow = Ext.extend(Ext.Window, {
createFeaturePanels : function()
{
var panels = this.features.map(function(feature){
var html = '<h2 class="k-whatsnew-text-title">' +
Ext.util.Format.htmlEncode(feature.title) +
'</h2><div class="k-whatsnew-text-description">' +
Ext.util.Format.nl2br(Ext.util.Format.htmlEncode(Zarafa.core.HTMLParser.br2nl(feature.description))) +
'</p>';
var html =
'<h2 class="k-whatsnew-text-title">' + feature.title + '</h2>' +
'<div class="k-whatsnew-text-description">' +
Ext.util.Format.nl2br(Zarafa.core.HTMLParser.br2nl(feature.description)) +
'</div>';
if ( !Ext.isEmpty(feature.icon_url) ){
html = '<img class="k-whatsnew-feature-icon" src="'+Ext.util.Format.htmlEncode(feature.icon_url)+'">' + html;
html = '<img class="k-whatsnew-feature-icon" src="' + feature.icon_url + '">' + html;
}
return {
......@@ -137,7 +137,7 @@ Zarafa.whatsnew.ui.WhatsNewWindow = Ext.extend(Ext.Window, {
cls: 'k-whatsnew-feature-image',
width: 432,
height: 287,
html: '<img src="'+Ext.util.Format.htmlEncode(feature.image_url)+'">'
html: '<img src="' + feature.image_url + '">'
}]
};
});
......
......@@ -124,6 +124,9 @@
// When set to true this disables the welcome screen to be shown for first time users.
define('DISABLE_WELCOME_SCREEN', false);
// Set to true to disable the "What's new dialog" that will be shown to users to introduce new features.
define('DISABLE_WHATS_NEW_DIALOG', false);
// When set to false it will disable showing of advanced settings.
define('ENABLE_ADVANCED_SETTINGS', false);
......
kopano-webapp (3.5.1~rc1+dfsg1-1) unstable; urgency=medium
* [1df56c9] debian/control: increase Standards-Version to 4.3.0
No further changes needed.
* [2b72826] d/control: remove npm package from B-D (again)
The npm package was a Build-Depends after kopano-webapp versions 3.4.22,
but no version of these releases was ever uploaded. npm isn't needed now
any more.
* [3756879] autopkgtest: create needed store before testing
Since kopanocore version > 8.6.0 the user needs to get a store, updating
the autopkgtest to fulfil this requirement.
* [32228fd] autopkgtest: update test to work in headless mode
The phantomjs driver in selenium is abandoned for some time, it's
suggested to work with the headless mode of the chromedriver or with
firefox.
Rework of the test to work with chromium in headless mode.
Thanks Guido for helping out with the lambda functions!
* [66c1e9e] New upstream version 3.5.1~rc1+dfsg1
* [878097f] rebuild patch queue from patch-queue branch
removed patch (fixed upstream):
server-do-not-define-JSONException-as-function.patch
* [748e428] autopkgtest: search correct CSS class names
Obviously the CSS class names have changed a bit more, we need to search
for other names now to login and send an email.
* [c56d0f3] autopkgtest: move over to Python3 based packages
* [6b4563d] d/control: increase depending version on php-mapi
The autopkgtest has detected that we need a recent version of php-mapi
(which is provided by the kopanocore package) with a version >= 8.6.92.
* [e1a92d4] k-w-common.install: also install the tokenizr JS file
The file tokenizr.min.js isn't installed by the Makefile from upstream,
working around this and pick the file directly from the source folder.
-- Carsten Schoenert <c.schoenert@t-online.de> Sun, 13 Jan 2019 12:52:59 +0100
kopano-webapp (3.5.0+dfsg1-1) unstable; urgency=medium
* [c7188ec] d/rules: detect PHP_VERSION dynamically
......
......@@ -25,7 +25,7 @@ Architecture: all
Depends:
kopano-contacts (>= 8.1.0),
php-gettext,
php-mapi (>= 8.6.90),
php-mapi (>= 8.6.92),
ssl-cert,
${misc:Depends},
Recommends:
......
......@@ -14,6 +14,7 @@ deploy/index.php usr/share/kopano-webapp
deploy/init.php usr/share/kopano-webapp
deploy/robots.txt usr/share/kopano-webapp
deploy/kopano.php usr/share/kopano-webapp
client/third-party/tokenizr/tokenizr.min.js usr/share/kopano-webapp/client/third-party
deploy/client/resources/fonts/KopanoWebAppDings.svg usr/share/fonts/svg/kopanowebapp
deploy/client/resources/fonts/kopanowebappdings.eot usr/share/fonts/eot/kopanowebapp
......
......@@ -3,18 +3,18 @@ Date: Thu, 5 Oct 2017 20:58:17 +0200
Subject: remove not valid es_CA.UTF-8 language
---
.../es_CA.UTF-8/LC_MESSAGES/zarafa_webapp.po | 6344 --------------------
.../es_CA.UTF-8/LC_MESSAGES/zarafa_webapp.po | 6337 --------------------
server/language/es_CA.UTF-8/language.txt | 1 -
2 files changed, 6345 deletions(-)
2 files changed, 6338 deletions(-)
delete mode 100644 server/language/es_CA.UTF-8/LC_MESSAGES/zarafa_webapp.po
delete mode 100644 server/language/es_CA.UTF-8/language.txt
diff --git a/server/language/es_CA.UTF-8/LC_MESSAGES/zarafa_webapp.po b/server/language/es_CA.UTF-8/LC_MESSAGES/zarafa_webapp.po
deleted file mode 100644
index 75ce00f..0000000
index f5fafff..0000000
--- a/server/language/es_CA.UTF-8/LC_MESSAGES/zarafa_webapp.po
+++ /dev/null
@@ -1,6344 +0,0 @@
@@ -1,6337 +0,0 @@
-# SOME DESCRIPTIVE TITLE.
-# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
-# This file is distributed under the same license as the PACKAGE package.
......@@ -23,7 +23,7 @@ index 75ce00f..0000000
-msgstr ""
-"Project-Id-Version: PACKAGE VERSION\n"
-"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2018-12-13 14:58+0100\n"
-"POT-Creation-Date: 2019-01-11 14:14+0100\n"
-"PO-Revision-Date: 2013-02-22 23:00+0200\n"
-"Last-Translator: Manuel <info@picholeiro.info>\n"
-"Language-Team: LANGUAGE <LL@li.org>\n"
......@@ -967,6 +967,10 @@ index 75ce00f..0000000
-msgid "No appointment selected"
-msgstr "No hay citas seleccionadas"
-
-#, fuzzy
-msgid "Create Appointment"
-msgstr "Nueva cita"
-
-msgid "Calendar"
-msgstr "Calendario"
-
......@@ -1635,12 +1639,6 @@ index 75ce00f..0000000
-msgid "Remove From Calendar"
-msgstr "Eliminar del calendario"
-
-msgid "Not Current"
-msgstr "No Actual"
-
-msgid "Meeting Request is out of date"
-msgstr "La solicitud de reunión está fuera de fecha"
-
-msgid "No Response Required"
-msgstr "La respuesta no es requerida"
-
......@@ -1669,9 +1667,6 @@ index 75ce00f..0000000
-msgid "View in calendar"
-msgstr "Ver varios calendarios en"
-
-msgid "This meeting request is out-of-date and will now be deleted."
-msgstr "Esta solicitud de reunión está fuera de fecha y ahora se eliminará."
-
-msgid ""
-"Your calendar has been updated automatically. This meeting request will now "
-"be deleted."
......@@ -2201,6 +2196,10 @@ index 75ce00f..0000000
-msgid "Edit recipient"
-msgstr "Editar recipiente"
-
-#, fuzzy
-msgid "Copy email address"
-msgstr "Nueva dirección de correo electrónico"
-
-msgid "Select attendees"
-msgstr "Seleccionar asistentes "
-
......@@ -2302,6 +2301,10 @@ index 75ce00f..0000000
-"deleted item can still be restored."
-msgstr ""
-
-#, fuzzy
-msgid "Kopano WebApp print"
-msgstr "Kopano WebApp"
-
-# 91%
-msgid "Display name"
-msgstr "Mostrar nombre"
......@@ -2320,24 +2323,13 @@ index 75ce00f..0000000
-msgid "Edit Recipient"
-msgstr "Editar recipiente"
-
-#, fuzzy
-msgid "Copy e-mail address"
-msgstr "Nueva dirección de correo electrónico"
-
-msgid "Send e-mail"
-msgstr "Enviar correo electrónico"
-msgid "Send email"
-msgstr "Enviar Correo Electrónico"
-
-#, fuzzy
-msgid "Delete recipient from suggestion list"
-msgstr "Borrar la Lista de Distribución."
-
-#, fuzzy
-msgid "Copy email address"
-msgstr "Nueva dirección de correo electrónico"
-
-msgid "Send email"
-msgstr "Enviar Correo Electrónico"
-
-msgid "View recipient"
-msgstr "Ver recipiente"
-
......@@ -4395,7 +4387,8 @@ index 75ce00f..0000000
-msgid "Open Shared Mails"
-msgstr "Abrir correos compartidos"
-
-msgid "Print single e-mail"
-#, fuzzy
-msgid "Print single email"
-msgstr "Imprimir solo este correo electrónico"