Merge pull request #45 from alexcloutier/feature/PreventInvitations

New user preference to prevent invitations
pull/47/head
Francis Lachapelle 2014-07-21 09:38:42 -04:00
commit f3ded6ce2a
8 changed files with 1867 additions and 1432 deletions

View File

@ -1,3 +1,4 @@
"This or these persons cannot be invited:" = "This or these persons cannot be invited:";
"Personal Calendar" = "Personal Calendar";
vevent_class0 = "(Public event)";
vevent_class1 = "(Private event)";

File diff suppressed because it is too large Load Diff

View File

@ -19,6 +19,7 @@
*/
#import <Foundation/NSCalendarDate.h>
#import <Foundation/NSDictionary.h>
#import <Foundation/NSPropertyList.h>
#import <Foundation/NSString.h>
#import <Foundation/NSTimeZone.h>
@ -41,6 +42,7 @@
#import <SOGo/NSString+Utilities.h>
#import <SOGo/SOGoUser.h>
#import <SOGo/SOGoUserDefaults.h>
#import <SOGo/SOGoUserSettings.h>
#import <SOGo/SOGoDomainDefaults.h>
#import <SOGo/SOGoSieveManager.h>
#import <SOGo/SOGoSystemDefaults.h>
@ -638,6 +640,47 @@ static NSArray *reminderValues = nil;
return [userDefaults busyOffHours];
}
- (NSArray *) whiteList
{
SOGoUserSettings *us;
NSMutableDictionary *moduleSettings;
NSArray *whiteList;
us = [user userSettings];
moduleSettings = [us objectForKey: @"Calendar"];
whiteList = [moduleSettings objectForKey:@"PreventInvitationsWhitelist"];
return whiteList;
}
- (void) setWhiteList: (NSArray *) whiteList
{
SOGoUserSettings *us;
NSMutableDictionary *moduleSettings;
us = [user userSettings];
moduleSettings = [us objectForKey: @"Calendar"];
[moduleSettings setObject: whiteList forKey: @"PreventInvitationsWhitelist"];
[us synchronize];
}
- (void) setPreventInvitations: (BOOL) preventInvitations
{
SOGoUserSettings *us;
NSMutableDictionary *moduleSettings;
us = [user userSettings];
moduleSettings = [us objectForKey: @"Calendar"];
[moduleSettings setObject: [NSNumber numberWithBool: preventInvitations] forKey: @"PreventInvitations"];
[us synchronize];
}
- (BOOL) preventInvitations
{
SOGoUserSettings *us;
NSMutableDictionary *moduleSettings;
us = [user userSettings];
moduleSettings = [us objectForKey: @"Calendar"];
return [[moduleSettings objectForKey: @"PreventInvitations"] boolValue];
}
- (NSArray *) firstWeekList
{
return [NSArray arrayWithObjects:

View File

@ -11,12 +11,15 @@
title="title"
const:popup="YES"
const:cssFiles="datepicker.css"
const:jsFiles="RowEditionController.js,PasswordPolicy.js,ckeditor/ckeditor.js,datepicker.js"
const:jsFiles="RowEditionController.js,PasswordPolicy.js,ckeditor/ckeditor.js,datepicker.js, SOGoAutoCompletion.js"
>
<script type="text/javascript">
var localeCode = '<var:string value="localeCode"/>';
</script>
<div class="popupMenu" id="contactsMenu">
<ul></ul>
</div>
<div id="colorPickerDialog" style="display: none;" class="dialog right bottom">
<div>
<span class="blc-FFFFFF"><!-- --></span>
@ -91,33 +94,33 @@
<span class="blc-99FF99"><!-- --></span>
</div>
</div>
<form id="mainForm" var:href="ownPath">
<div class="tabsContainer" id="preferencesTabs">
<ul>
<li target="generalView"><span>
<var:string label:value="General" /></span></li>
<var:if condition="userHasCalendarAccess">
<var:string label:value="General" /></span></li>
<var:if condition="userHasCalendarAccess">
<li target="calendarOptionsView"><span><var:string
label:value="Calendar Options"/></span></li>
</var:if
><li target="contactsOptionsView"><span><var:string
label:value="Contacts Options"/></span></li
><var:if condition="userHasMailAccess">
label:value="Calendar Options"/></span></li>
</var:if
><li target="contactsOptionsView"><span><var:string
label:value="Contacts Options"/></span></li
><var:if condition="userHasMailAccess">
<li target="mailOptionsView"><span><var:string
label:value="Mail Options"/></span></li>
label:value="Mail Options"/></span></li>
<li target="mailAccountsView"><span><var:string
label:value="IMAP Accounts"/></span></li>
label:value="IMAP Accounts"/></span></li>
<var:if condition="isVacationEnabled"><li target="vacationView"><span><var:string
label:value="Vacation"/></span></li></var:if
><var:if condition="isForwardEnabled"><li target="forwardView"><span><var:string
label:value="Forward"/></span></li></var:if>
</var:if
><var:if condition="shouldDisplayAdditionalPreferences">
label:value="Vacation"/></span></li></var:if
><var:if condition="isForwardEnabled"><li target="forwardView"><span><var:string
label:value="Forward"/></span></li></var:if>
</var:if
><var:if condition="shouldDisplayAdditionalPreferences">
<li target="additionalView"><span>
<var:string label:value="Additional Parameters"/></span></li>
</var:if
><var:if condition="shouldDisplayPasswordChange">
<var:string label:value="Additional Parameters"/></span></li>
</var:if
><var:if condition="shouldDisplayPasswordChange">
<li target="passwordView"><span><var:string label:value="Password"/></span></li>
</var:if>
</ul>
@ -128,38 +131,38 @@
<dd><var:string value="sogoVersion"/></dd>
<dt><var:string label:value="Language :"/></dt>
<dd><var:popup list="languages" item="item"
const:id="language"
const:name="language"
string="languageText"
selection="language"
label:noSelectionString="choose" /></dd>
const:id="language"
const:name="language"
string="languageText"
selection="language"
label:noSelectionString="choose" /></dd>
<dt><var:string label:value="Current Time Zone :"/></dt>
<dd><var:popup list="timeZonesList" item="item"
const:id="timezone"
const:name="timezone"
string="item" selection="userTimeZone" /></dd>
const:id="timezone"
const:name="timezone"
string="item" selection="userTimeZone" /></dd>
<dt><var:string label:value="Short Date Format :"/></dt>
<dd><var:popup list="shortDateFormatsList" item="item"
const:id="shortDateFormat"
const:name="shortDateFormat"
string="itemShortDateFormatText" selection="userShortDateFormat"/></dd>
const:id="shortDateFormat"
const:name="shortDateFormat"
string="itemShortDateFormatText" selection="userShortDateFormat"/></dd>
<dt><var:string label:value="Long Date Format :"/></dt>
<dd><var:popup list="longDateFormatsList" item="item"
const:id="longDateFormat"
const:name="longDateFormat"
string="itemLongDateFormatText" selection="userLongDateFormat"
/></dd>
const:id="longDateFormat"
const:name="longDateFormat"
string="itemLongDateFormatText" selection="userLongDateFormat"
/></dd>
<dt><var:string label:value="Time Format :"/></dt>
<dd><var:popup list="timeFormatsList" item="item"
const:id="timeFormat"
const:name="timeFormat"
string="itemTimeFormatText" selection="userTimeFormat"
/></dd>
const:id="timeFormat"
const:name="timeFormat"
string="itemTimeFormatText" selection="userTimeFormat"
/></dd>
<dt><var:string label:value="Default module :"/></dt>
<dd><var:popup list="availableModules" item="item"
const:id="defaultModule"
const:name="defaultModule"
string="itemModuleText" selection="userDefaultModule"/></dd>
const:id="defaultModule"
const:name="defaultModule"
string="itemModuleText" selection="userDefaultModule"/></dd>
</dl>
</div>
<var:if condition="userHasCalendarAccess">
@ -167,88 +170,132 @@
<dl class="dl-horizontal">
<dt><var:string label:value="Week begins on :"/></dt>
<dd><var:popup list="daysList" item="item"
const:id="weekStartDay"
const:name="weekStartDay"
string="itemWeekStartDay" selection="userWeekStartDay"/></dd>
const:id="weekStartDay"
const:name="weekStartDay"
string="itemWeekStartDay" selection="userWeekStartDay"/></dd>
<dt><var:string label:value="Day start time :"/></dt>
<dd><var:popup list="hoursList" item="item"
const:id="dayStartTime"
const:name="dayStartTime"
string="item" selection="userDayStartTime"/></dd>
const:id="dayStartTime"
const:name="dayStartTime"
string="item" selection="userDayStartTime"/></dd>
<dt><var:string label:value="Day end time :"/></dt>
<dd><var:popup list="hoursList" item="item"
const:id="dayEndTime"
const:name="dayEndTime"
string="item" selection="userDayEndTime"/></dd>
const:id="dayEndTime"
const:name="dayEndTime"
string="item" selection="userDayEndTime"/></dd>
<dt></dt>
<dd><input type="checkbox"
const:name="busyOffHours"
const:id="busyOffHours"
var:checked="busyOffHours" />
<dd><input type="checkbox"
const:name="busyOffHours"
const:id="busyOffHours"
var:checked="busyOffHours" />
<var:string label:value="Show time as busy outside working hours"/></dd>
<dt><var:string label:value="First week of year :"/></dt>
<dd><var:popup list="firstWeekList" item="item"
const:id="firstWeek"
const:name="firstWeek"
string="itemFirstWeekText" selection="userFirstWeek"/></dd>
<dt><var:string label:value="Default calendar :"/></dt>
<dd><var:popup list="defaultCalendarList" item="item"
const:id="defaultCalendar"
const:name="defaultCalendar"
string="itemCalendarText" selection="userDefaultCalendar"/></dd>
<dt><var:string label:value="Default events classification :"/></dt>
<dd><var:popup list="calendarClassificationsList" item="item"
const:id="eventsClassification"
const:name="eventsClassification"
string="itemClassificationText" selection="eventsDefaultClassification"/></dd>
<dt><var:string label:value="Default tasks classification :"/></dt>
<dd><var:popup list="calendarClassificationsList" item="item"
const:id="tasksClassification"
const:name="tasksClassification"
string="itemClassificationText" selection="tasksDefaultClassification"/></dd>
<dt><var:string label:value="Default reminder :"/></dt>
<dd><var:popup list="reminderList" item="item"
const:disabledValue="-"
label:noSelectionString="reminder_NONE"
const:name="reminderList"
const:id="reminderList"
string="itemReminderText" var:selection="reminder"/></dd>
<dt><var:string label:value="First week of year :"/></dt>
<dd><var:popup list="firstWeekList" item="item"
const:id="firstWeek"
const:name="firstWeek"
string="itemFirstWeekText" selection="userFirstWeek"/></dd>
<dt><var:string label:value="Default calendar :"/></dt>
<dd><var:popup list="defaultCalendarList" item="item"
const:id="defaultCalendar"
const:name="defaultCalendar"
string="itemCalendarText" selection="userDefaultCalendar"/></dd>
<dt><var:string label:value="Default events classification :"/></dt>
<dd><var:popup list="calendarClassificationsList" item="item"
const:id="eventsClassification"
const:name="eventsClassification"
string="itemClassificationText" selection="eventsDefaultClassification"/></dd>
<dt><var:string label:value="Default tasks classification :"/></dt>
<dd><var:popup list="calendarClassificationsList" item="item"
const:id="tasksClassification"
const:name="tasksClassification"
string="itemClassificationText" selection="tasksDefaultClassification"/></dd>
<dt><var:string label:value="Default reminder :"/></dt>
<dd><var:popup list="reminderList" item="item"
const:disabledValue="-"
label:noSelectionString="reminder_NONE"
const:name="reminderList"
const:id="reminderList"
string="itemReminderText" var:selection="reminder"/></dd>
</dl>
<label><var:string label:value="Categories"/></label>
<div id="calendarCategoriesListWrapper" class="listWrapper"
><table class="categoriesList" cellspacing="0">
<thead>
<tr class="tableview"
><th const:class="tbtv_headercell" const:id="nameTableHeader"
><var:string label:value="Name"/></th
><th const:class="tbtv_headercell" const:id="colorTableHeader"
><var:string label:value="Color"/></th
></tr
></thead>
<tbody>
<var:foreach list="calendarCategoryList" item="category">
<tr const:class="categoryListRow"
><td const:class="categoryListCell"
><var:string var:value="category"/></td
><td const:class="categoryListCell"
><div const:class="colorBox" var:data-color="categoryColor"><entity name="nbsp"/></div></td
></tr>
</var:foreach>
</tbody>
</table>
</div>
<div class="bottomToolbar">
<a const:id="calendarCategoryAdd" class="bottomButton" href="#">
<span><img rsrc:src="add-icon.png" label:title="Add" />
</span></a>
<a const:id="calendarCategoryDelete" class="bottomButton" href="#">
<span><img rsrc:src="remove-icon.png" label:title="Delete" />
</span></a>
</div>
<input type="hidden" const:id="calendarCategoriesValue"
const:name="calendarCategoriesValue" var:value="calendarCategoriesValue"/>
</div>
<div class="tabsContainer" id="calendarOptionsTabs">
<ul>
<li target="calendarCategoriesView">
<span><var:string label:value="Categories"/></span></li>
<li target="calendarAppointmentsInvitationsView">
<span><var:string label:value="Appointments invitations"/></span></li>
</ul>
<div class="tabs">
<div id="calendarCategoriesView" class="tab">
<div id="calendarCategoriesListWrapper" class="listWrapper">
<table class="categoriesList" cellspacing="0">
<thead>
<tr class="tableview">
<th const:class="tbtv_headercell" const:id="nameTableHeader">
<var:string label:value="Name"/></th>
<th const:class="tbtv_headercell" const:id="colorTableHeader">
<var:string label:value="Color"/></th>
</tr>
</thead>
<tbody>
<var:foreach list="calendarCategoryList" item="category">
<tr const:class="categoryListRow">
<td const:class="categoryListCell">
<var:string var:value="category"/></td>
<td const:class="categoryListCell">
<div const:class="colorBox" var:data-color="categoryColor"><entity name="nbsp"/></div></td>
</tr>
</var:foreach>
</tbody>
</table>
</div><!-- #calendarCategoriesListWrapper -->
<div class="bottomToolbar">
<a const:id="calendarCategoryAdd" class="bottomButton" href="#">
<span><img rsrc:src="add-icon.png" label:title="Add" /></span></a>
<a const:id="calendarCategoryDelete" class="bottomButton" href="#">
<span><img rsrc:src="remove-icon.png" label:title="Delete" /> </span></a>
</div><!-- .bottomToolbar -->
<input type="hidden" const:id="calendarCategoriesValue"
const:name="calendarCategoriesValue" var:value="calendarCategoriesValue"/>
</div><!-- #calendarCategoriesView -->
<div id="calendarAppointmentsInvitationsView" class="tab">
<div><input type="checkbox"
const:name="preventInvitations"
const:id="preventInvitations"
var:checked="preventInvitations" />
<var:string label:value="Prevent from being invited to appointments"/></div>
<hr />
<var:string label:value="White list for appointments invitations:"/>
<div id="appointmentsWhiteListWrapper" class="listWrapper">
<table id="tableViewWhiteList" cellspacing="0">
<thead>
<tr class="tableview">
<th const:class="tbtv_headercell" const:id="whiteListTableHeader">
<var:string label:value="Contacts names"/></th>
</tr>
</thead>
<tbody>
<var:foreach list="appointmentsWhiteList" item="contact">
<tr const:class="whiteListRow">
<td const:class="whiteListCell">
<var:string var:value="contact"/></td>
</tr>
</var:foreach>
</tbody>
</table>
</div><!-- #appointmentsWhiteListWrapper -->
<div class="bottomToolbar">
<a const:id="appointmentsWhiteListAdd" class="bottomButton" href="#">
<span><img rsrc:src="add-icon.png" label:title="Add" /></span></a>
<a const:id="appointmentsWhiteListDelete" class="bottomButton" href="#">
<span><img rsrc:src="remove-icon.png" label:title="Delete" /></span></a>
</div><!-- .bottomToolbar -->
<input type="hidden" const:id="whiteList"
const:name="whiteList" var:value="whiteList"/>
</div><!-- #calendarAppointmentsInvitationsView -->
</div><!-- .tabs -->
</div><!-- #calendarOptionsTabs -->
</div><!-- #calendarOptionsView -->
</var:if>
<div id="contactsOptionsView" class="tab">
<label><var:string label:value="Categories"/></label>
@ -258,14 +305,14 @@
<tr class="tableview"
><th const:class="tbtv_headercell" const:id="nameTableHeader"
><var:string label:value="Name"/></th
></tr
></thead>
></tr
></thead>
<tbody>
<var:foreach list="contactsCategoryList" item="category">
<tr const:class="categoryListRow"
><td const:class="categoryListCell"
><var:string var:value="category"/></td
></tr>
></tr>
</var:foreach>
</tbody>
</table>
@ -278,135 +325,135 @@
<span><img rsrc:src="remove-icon.png" label:title="Delete" />
</span></a>
</div>
<input type="hidden" const:id="contactsCategoriesValue"
const:name="contactsCategoriesValue" var:value="contactsCategoriesValue"/>
<input type="hidden" const:id="contactsCategoriesValue"
const:name="contactsCategoriesValue" var:value="contactsCategoriesValue"/>
</div>
<var:if condition="userHasMailAccess">
<div id="mailOptionsView" class="tab">
<dl class="dl-horizontal">
<dt></dt>
<dd><input type="checkbox"
const:name="subscribedFoldersOnly"
const:id="subscribedFoldersOnly"
var:checked="showSubscribedFoldersOnly" />
<var:string label:value="Show subscribed mailboxes only"/></dd>
<dt></dt>
<dd><input type="checkbox"
const:name="sortByThreads"
const:id="sortByThreads"
var:checked="sortByThreads" />
<var:string label:value="Sort messages by threads"/></dd>
<dd><input type="checkbox"
const:name="addOutgoingAddresses"
const:id="addOutgoingAddresses"
var:checked="addOutgoingAddresses"
onChange = "onAddOutgoingAddressesCheck(this);"/>
<var:string label:value="When sending mail, add unknown recipients to my"/><br/>
<var:popup list="addressBookList" item="item"
const:id="addressBookList"
const:name="addressBookList"
string="itemAddressBookText" selection="userAddressBook"/></dd>
const:name="subscribedFoldersOnly"
const:id="subscribedFoldersOnly"
var:checked="showSubscribedFoldersOnly" />
<var:string label:value="Show subscribed mailboxes only"/></dd>
<dt></dt>
<dd><input type="checkbox"
const:name="sortByThreads"
const:id="sortByThreads"
var:checked="sortByThreads" />
<var:string label:value="Sort messages by threads"/></dd>
<dd><input type="checkbox"
const:name="addOutgoingAddresses"
const:id="addOutgoingAddresses"
var:checked="addOutgoingAddresses"
onChange = "onAddOutgoingAddressesCheck(this);"/>
<var:string label:value="When sending mail, add unknown recipients to my"/><br/>
<var:popup list="addressBookList" item="item"
const:id="addressBookList"
const:name="addressBookList"
string="itemAddressBookText" selection="userAddressBook"/></dd>
<dt></dt>
<dt><var:string label:value="Check for new mail:"/></dt>
<dd><var:popup list="messageCheckList" item="item"
const:id="messageCheck"
const:name="messageCheck"
string="itemMessageCheckText" selection="userMessageCheck"/></dd>
const:id="messageCheck"
const:name="messageCheck"
string="itemMessageCheckText" selection="userMessageCheck"/></dd>
<dt><var:string label:value="Forward messages:"/></dt>
<dd><var:popup list="messageForwardingList" item="item"
const:id="messageForwarding"
const:name="messageForwarding"
string="itemMessageForwardingText"
selection="userMessageForwarding"/></dd>
const:id="messageForwarding"
const:name="messageForwarding"
string="itemMessageForwardingText"
selection="userMessageForwarding"/></dd>
<dt><var:string label:value="When replying to a message:"/></dt>
<dd><var:popup list="replyPlacementList" item="item"
const:id="replyPlacementList"
const:name="replyPlacementList"
string="itemReplyPlacementText"
selection="userReplyPlacement"/></dd>
const:id="replyPlacementList"
const:name="replyPlacementList"
string="itemReplyPlacementText"
selection="userReplyPlacement"/></dd>
<dt><var:string label:value="And place my signature"/></dt>
<dd><var:popup list="signaturePlacementList" item="item"
const:id="signaturePlacementList"
const:name="signaturePlacementList"
string="itemSignaturePlacementText"
selection="userSignaturePlacement"/></dd>
const:id="signaturePlacementList"
const:name="signaturePlacementList"
string="itemSignaturePlacementText"
selection="userSignaturePlacement"/></dd>
<dt><var:string label:value="Compose messages in"/></dt>
<dd><var:popup list="composeMessagesType" item="item"
const:id="composeMessagesType"
const:name="composeMessagesType"
string="itemComposeMessagesText"
selection="userComposeMessagesType"/></dd>
const:id="composeMessagesType"
const:name="composeMessagesType"
string="itemComposeMessagesText"
selection="userComposeMessagesType"/></dd>
<dt><var:string label:value="Display remote inline images"/></dt>
<dd><var:popup list="displayRemoteInlineImages" item="item"
const:id="displayRemoteInlineImages"
const:name="displayRemoteInlineImages"
string="itemDisplayRemoteInlineImagesText"
selection="userDisplayRemoteInlineImages"/></dd>
const:id="displayRemoteInlineImages"
const:name="displayRemoteInlineImages"
string="itemDisplayRemoteInlineImagesText"
selection="userDisplayRemoteInlineImages"/></dd>
</dl>
<div class="tabsContainer" id="mailOptionsTabs">
<ul>
<var:if condition="isSieveScriptsEnabled"
><li target="mailFiltersView"><span><var:string
label:value="Filters"/></span></li
></var:if>
><li target="mailFiltersView"><span><var:string
label:value="Filters"/></span></li
></var:if>
<li target="mailLabelsView"><span><var:string
label:value="Labels"/></span></li>
label:value="Labels"/></span></li>
</ul>
<div class="tabs">
<var:if condition="isSieveScriptsEnabled"
><div id="mailFiltersView" class="tab">
<script type="text/javascript">
var sieveCapabilities = <var:string value="sieveCapabilities" const:escapeHTML="NO"/>;
</script>
<div id="filtersListWrapper" class="listWrapper">
<table id="filtersList" cellspacing="0">
<thead>
<tr class="tableview">
<th const:class="tbtv_headercell" const:id="nameTableHeader"
><div id="mailFiltersView" class="tab">
<script type="text/javascript">
var sieveCapabilities = <var:string value="sieveCapabilities" const:escapeHTML="NO"/>;
</script>
<div id="filtersListWrapper" class="listWrapper">
<table id="filtersList" cellspacing="0">
<thead>
<tr class="tableview">
<th const:class="tbtv_headercell" const:id="nameTableHeader"
><var:string label:value="Name" /></th>
<th const:class="tbtv_headercell" const:id="activeTableHeader"
<th const:class="tbtv_headercell" const:id="activeTableHeader"
><var:string label:value="Active" /></th>
</tr>
</thead>
<tbody><!--space --></tbody>
</table>
<input type="hidden" const:name="sieveFilters" const:id="sieveFilters"
var:value="sieveFiltersValue"/>
</div><!-- #filtersListWrapper -->
<div class="bottomToolbar">
<a const:id="filterAdd" class="bottomButton" href="#">
<span><img rsrc:src="add-icon.png" label:title="Add" /></span></a>
<a const:id="filterDelete" class="bottomButton" href="#">
<span><img rsrc:src="remove-icon.png" label:title="Delete" /></span></a>
<a const:id="filterMoveUp" class="bottomButton" href="#">
<span><img rsrc:src="up-icon.png" label:title="Move Up" /></span></a>
<a const:id="filterMoveDown" class="bottomButton" href="#">
<span><img rsrc:src="down-icon.png" label:title="Move Down" /></span></a>
</div><!-- .bottomToolbar -->
</div
></var:if><!-- #mailFiltersView -->
</tr>
</thead>
<tbody><!--space --></tbody>
</table>
<input type="hidden" const:name="sieveFilters" const:id="sieveFilters"
var:value="sieveFiltersValue"/>
</div><!-- #filtersListWrapper -->
<div class="bottomToolbar">
<a const:id="filterAdd" class="bottomButton" href="#">
<span><img rsrc:src="add-icon.png" label:title="Add" /></span></a>
<a const:id="filterDelete" class="bottomButton" href="#">
<span><img rsrc:src="remove-icon.png" label:title="Delete" /></span></a>
<a const:id="filterMoveUp" class="bottomButton" href="#">
<span><img rsrc:src="up-icon.png" label:title="Move Up" /></span></a>
<a const:id="filterMoveDown" class="bottomButton" href="#">
<span><img rsrc:src="down-icon.png" label:title="Move Down" /></span></a>
</div><!-- .bottomToolbar -->
</div
></var:if><!-- #mailFiltersView -->
<div id="mailLabelsView" class="tab">
<div id="mailLabelsListWrapper" class="listWrapper">
<table id="labelsList" cellspacing="0">
<thead>
<tr class="tableview">
<th const:class="tbtv_headercell" const:id="labelTableHeader"
><var:string label:value="Label"/></th>
><var:string label:value="Label"/></th>
<th const:class="tbtv_headercell" const:id="colorTableHeader"
><var:string label:value="Color"/></th>
><var:string label:value="Color"/></th>
</tr>
</thead>
<tbody>
<var:foreach list="mailLabelList" item="label"
><tr var:data-name="label.name" const:class="labelListRow">
<td const:class="labelListCell"
><tr var:data-name="label.name" const:class="labelListRow">
<td const:class="labelListCell"
><var:string var:value="label.label"/></td>
<td const:class="labelListCell">
<div const:class="colorBox" var:data-color="label.color"><entity name="nbsp"/></div>
</td>
</tr>
<td const:class="labelListCell">
<div const:class="colorBox" var:data-color="label.color"><entity name="nbsp"/></div>
</td>
</tr>
</var:foreach>
</tbody>
</table>
@ -414,33 +461,33 @@
<div class="bottomToolbar">
<a const:id="mailLabelAdd" class="bottomButton" href="#">
<span><img rsrc:src="add-icon.png" label:title="Add" />
</span></a>
</span></a>
<a const:id="mailLabelDelete" class="bottomButton" href="#">
<span><img rsrc:src="remove-icon.png" label:title="Delete" />
</span></a>
</span></a>
</div><!-- .bottomToolbar -->
<input type="hidden" const:id="mailLabelsValue"
const:name="mailLabelsValue" var:value="mailLabelsValue"/>
const:name="mailLabelsValue" var:value="mailLabelsValue"/>
</div><!-- #mailLabelsView -->
</div><!-- .tabs -->
</div><!-- #mailOptionsTabs -->
</div><!-- #mailOptionsView -->
<div id="mailAccountsView" class="tab">
<input type="hidden" const:name="mailAccountsJSON" const:id="mailAccountsJSON"
var:value="mailAccounts"/>
var:value="mailAccounts"/>
<div id="mailAccountsListWrapper" class="listWrapper"
><ul id="mailAccountsList"
><!-- space --></ul
></div>
><ul id="mailAccountsList"
><!-- space --></ul
></div>
<var:if condition="mailAuxiliaryUserAccountsEnabled">
<div const:id="mailAccountsToolbar" class="bottomToolbar">
<a const:id="mailAccountAdd" class="bottomButton" href="#">
<span><img rsrc:src="add-icon.png" label:title="Add" />
</span></a>
</span></a>
<a const:id="mailAccountDelete" class="bottomButton" href="#">
<span><img rsrc:src="remove-icon.png" label:title="Delete" />
</span></a>
</span></a>
</div>
</var:if>
<div id="mailAccountEditor">
@ -448,15 +495,15 @@
<dl class="dl-horizontal">
<dt><var:string label:value="Server Name:"/></dt>
<dd><input const:name="serverName" const:id="serverName" type="text" const:value=""/>
<var:string label:value="Port:"/>
<input const:name="port" const:id="port" type="text" const:value=""/></dd>
<var:string label:value="Port:"/>
<input const:name="port" const:id="port" type="text" const:value=""/></dd>
<dt><var:string label:value="Encryption:"/></dt>
<dd><input const:name="encryption" type="radio" const:value="none"/>
<var:string label:value="None"/>
<input const:name="encryption" type="radio" const:value="ssl"/>
<var:string label:value="SSL"/>
<input const:name="encryption" type="radio" const:value="tls"/>
<var:string label:value="TLS"/></dd>
<var:string label:value="None"/>
<input const:name="encryption" type="radio" const:value="ssl"/>
<var:string label:value="SSL"/>
<input const:name="encryption" type="radio" const:value="tls"/>
<var:string label:value="TLS"/></dd>
<dt><var:string label:value="User Name:"/></dt>
<dd><input const:name="userName" const:id="userName" type="text" const:value=""/></dd>
<dt><var:string label:value="Password:"/></dt>
@ -464,11 +511,11 @@
</dl>
<input const:name="encryption" type="hidden" const:value="none"/>
</fieldset>
<script type="text/javascript">
var mailCustomFromEnabled = <var:string value="mailCustomFromEnabled" const:escapeHTML="NO"/>;
</script>
<fieldset const:id="identityInfo">
<dl class="dl-horizontal">
<dt><var:string label:value="Full Name:"/></dt>
@ -481,40 +528,40 @@
<dd><span id="actSignature"><!--space --></span></dd>
</dl>
</fieldset>
<fieldset const:id="returnReceiptsInfo">
<var:string
label:value="When I receive a request for a return receipt:"
/><br/>
label:value="When I receive a request for a return receipt:"
/><br/>
<label><input const:name="receipt-action" const:id="receipt-action-ignore"
type="radio" const:value="ignore"/>
type="radio" const:value="ignore"/>
<var:string
label:value="Never send a return receipt"/></label
><br/>
label:value="Never send a return receipt"/></label
><br/>
<label><input const:name="receipt-action" const:id="receipt-action-allow"
type="radio" const:value="allow"/>
type="radio" const:value="allow"/>
<var:string
label:value="Allow return receipts for some messages"/></label
><br/>
label:value="Allow return receipts for some messages"/></label
><br/>
<div id="receiptOptions">
<var:string
label:value="If I'm not in the To or Cc of the message:"/>
label:value="If I'm not in the To or Cc of the message:"/>
<select name="receipt-non-recipient-action" id="receipt-non-recipient-action">
<option const:value="ignore"><var:string label:value="Never send"/></option>
<option const:value="send"><var:string label:value="Always send"/></option>
<option const:value="ask"><var:string label:value="Ask me"/></option>
</select><br/>
<var:string
label:value="If the sender is outside my domain:"/>
label:value="If the sender is outside my domain:"/>
<select name="receipt-outside-domain-action" id="receipt-outside-domain-action">
<option const:value="ignore"><var:string label:value="Never send"/></option>
<option const:value="send"><var:string label:value="Always send"/></option>
<option const:value="ask"><var:string label:value="Ask me"/></option>
</select><br/>
<var:string
label:value="In all other cases:"/>
label:value="In all other cases:"/>
<select name="receipt-any-action" id="receipt-any-action">
<option const:value="ignore"><var:string label:value="Never send"/></option>
<option const:value="send"><var:string label:value="Always send"/></option>
@ -524,79 +571,79 @@
</fieldset>
</div>
</div>
<var:if condition="isVacationEnabled">
<div id="vacationView" class="tab">
<label><input type="checkbox"
const:name="enableVacation"
const:id="enableVacation"
var:checked="enableVacation" />
<label><input type="checkbox"
const:name="enableVacation"
const:id="enableVacation"
var:checked="enableVacation" />
<var:string label:value="Enable vacation auto reply"/></label>
<div id="vacation">
<label><var:string label:value="Auto reply message :"/><br/>
<textarea const:name="autoReplyText"
const:id="autoReplyText"
var:value="autoReplyText"/>
const:id="autoReplyText"
var:value="autoReplyText"/>
</label><br/>
<label><var:string label:value="Email addresses (separated by commas) :"/><br/>
<input type="hidden"
const:id="defaultEmailAddresses"
var:value="defaultEmailAddresses" />
const:id="defaultEmailAddresses"
var:value="defaultEmailAddresses" />
<textarea const:name="autoReplyEmailAddresses"
const:id="autoReplyEmailAddresses"
var:value="autoReplyEmailAddresses" /><br/>
const:id="autoReplyEmailAddresses"
var:value="autoReplyEmailAddresses" /><br/>
<span><a href="#" class="button" id="addDefaultEmailAddresses"><span>
<var:string label:value="Add default email addresses" /></span></a>
<var:string label:value="Add default email addresses" /></span></a>
</span>
</label><br/>
<label><var:string label:value="Days between responses :"/>
<label><var:string label:value="Days between responses :"/>
<var:popup list="daysBetweenResponsesList" item="item"
const:id="daysBetweenResponsesList"
const:name="daysBetweenResponsesList"
string="item"
selection="daysBetweenResponses" /></label><br/>
<label><input type="checkbox"
const:name="ignoreLists"
const:id="ignoreLists"
var:checked="ignoreLists" />
const:id="daysBetweenResponsesList"
const:name="daysBetweenResponsesList"
string="item"
selection="daysBetweenResponses" /></label><br/>
<label><input type="checkbox"
const:name="ignoreLists"
const:id="ignoreLists"
var:checked="ignoreLists" />
<var:string label:value="Do not send responses to mailing lists" /></label><br/>
<label class="timeDate"><input var:checked="enableVacationEndDate"
const:name="enableVacationEndDate" const:id="enableVacationEndDate" type="checkbox" class="checkBox"
/><var:string label:value="Disable auto reply on" /></label><var:component className="UIxTimeDateControl"
const:displayTimeControl="0"
var:disabled="disableVacationEndDate"
const:controlID="vacationEndDate"
date="vacationEndDate"
const:dayStartHour="0"
const:dayEndHour="23"
const:name="enableVacationEndDate" const:id="enableVacationEndDate" type="checkbox" class="checkBox"
/><var:string label:value="Disable auto reply on" /></label><var:component className="UIxTimeDateControl"
const:displayTimeControl="0"
var:disabled="disableVacationEndDate"
const:controlID="vacationEndDate"
date="vacationEndDate"
const:dayStartHour="0"
const:dayEndHour="23"
/>
</div>
</div>
</var:if
><var:if condition="isForwardEnabled">
</var:if
><var:if condition="isForwardEnabled">
<div id="forwardView" class="tab">
<label><input type="checkbox"
const:name="enableForward"
const:id="enableForward"
var:checked="enableForward" />
<label><input type="checkbox"
const:name="enableForward"
const:id="enableForward"
var:checked="enableForward" />
<var:string label:value="Forward incoming messages"/></label><br/>
<div id="forward">
<label><var:string label:value="Email addresses (separated by commas) :"/><br/>
<textarea const:name="forwardAddress"
const:id="forwardAddress"
var:value="forwardAddress" />
const:id="forwardAddress"
var:value="forwardAddress" />
</label><br/>
<label><input type="checkbox"
const:name="forwardKeepCopy"
const:id="forwardKeepCopy"
var:checked="forwardKeepCopy" />
<label><input type="checkbox"
const:name="forwardKeepCopy"
const:id="forwardKeepCopy"
var:checked="forwardKeepCopy" />
<var:string label:value="Keep a copy" /></label><br/>
</div>
</div>
@ -605,23 +652,23 @@
<var:if condition="shouldDisplayPasswordChange">
<div id="passwordView" class="tab">
<p id="passwordFields"><label><var:string label:value="New password:"
/><input const:id="newPasswordField" class="textField"
type="password" const:value=""/></label><br/>
<label><var:string label:value="Confirmation:"
/><input const:id="newPasswordConfirmationField" class="textField"
type="password" const:value=""/></label><br/>
<a href="#" class="button" id="changePasswordBtn"
><span><var:string label:value="Change"/></span></a><br/>
/><input const:id="newPasswordField" class="textField"
type="password" const:value=""/></label><br/>
<label><var:string label:value="Confirmation:"
/><input const:id="newPasswordConfirmationField" class="textField"
type="password" const:value=""/></label><br/>
<a href="#" class="button" id="changePasswordBtn"
><span><var:string label:value="Change"/></span></a><br/>
</p>
<p id="passwordError"><!-- space --></p>
</div>
</var:if
><var:if condition="shouldDisplayAdditionalPreferences"
</var:if
><var:if condition="shouldDisplayAdditionalPreferences"
><div id="additionalView" class="tab">
<var:component className="UIxAdditionalPreferences"/>
</div></var:if>
<input type="hidden" id="hasChanged" name="hasChanged"
var:value="hasChanged"/>
var:value="hasChanged"/>
</div>
</div>
</form>

View File

@ -2,277 +2,384 @@
// NOTE: The popup menu with id "contactsMenu" must exist before
// using this interface.
//
//
// This interface fires two events:
// - autocompletion:changed : fired when a new contact is selected
// - autocompletion:changedlist : fired when a new list is selected
//
var SOGoAutoCompletionInterface = {
// Attributes that could be changed from the object
// inheriting the inteface
uidField: "c_name",
addressBook: null,
excludeGroups: false,
excludeLists: false,
// Internal attributes
animationParent: null,
selectedIndex: -1,
delay: 0.750,
delayedSearch: false,
menu: null,
bind: function () {
this.menu = $('contactsMenu');
this.writeAttribute("autocomplete", "off");
this.writeAttribute("container", null);
this.confirmedValue = null;
this.observe("keydown", this.onKeydown.bindAsEventListener(this));
this.observe("blur", this.onBlur.bindAsEventListener(this));
},
onKeydown: function (event) {
if (event.ctrlKey || event.metaKey) {
this.focussed = true;
return;
}
if (event.keyCode == Event.KEY_TAB) {
if (this.confirmedValue)
this.value = this.confirmedValue;
else
this.writeAttribute("uid", null);
if (document.currentPopupMenu)
hideMenu(document.currentPopupMenu);
}
else if (event.keyCode == 0
|| event.keyCode == Event.KEY_BACKSPACE
|| event.keyCode == Event.KEY_DELETE
|| event.keyCode == 32 // Space
|| event.keyCode > 47) {
this.confirmedValue = null;
this.selectedIndex = -1;
if (this.delayedSearch)
window.clearTimeout(this.delayedSearch);
this.delayedSearch = this.performSearch.delay(this.delay, this);
}
else if (event.keyCode == Event.KEY_RETURN) {
preventDefault(event);
if (this.confirmedValue)
this.value = this.confirmedValue;
else
this.writeAttribute("uid", null);
if (document.currentPopupMenu)
hideMenu(document.currentPopupMenu);
this.selectedIndex = -1;
if (this.readAttribute("container")) {
this.confirmedValue = null;
this.fire("autocompletion:changedlist", this.readAttribute("container"));
}
else
this.fire("autocompletion:changed", event.keyCode);
}
else if (this.menu.getStyle('visibility') == 'visible') {
if (event.keyCode == Event.KEY_UP) { // Up arrow
if (this.selectedIndex > 0) {
var contacts = this.menu.select("li");
contacts[this.selectedIndex--].removeClassName("selected");
this.value = contacts[this.selectedIndex].readAttribute("address");
this.confirmedValue = this.value;
this.writeAttribute("uid", contacts[this.selectedIndex].readAttribute("uid"));
contacts[this.selectedIndex].addClassName("selected");
var container = contacts[this.selectedIndex].readAttribute("container");
if (container)
this.writeAttribute("container", container);
}
}
else if (event.keyCode == Event.KEY_DOWN) { // Down arrow
var contacts = this.menu.select("li");
if (contacts.size() - 1 > this.selectedIndex) {
if (this.selectedIndex >= 0)
contacts[this.selectedIndex].removeClassName("selected");
this.selectedIndex++;
this.value = contacts[this.selectedIndex].readAttribute("address");
this.confirmedValue = this.value;
this.writeAttribute("uid", contacts[this.selectedIndex].readAttribute("uid"));
contacts[this.selectedIndex].addClassName("selected");
var container = contacts[this.selectedIndex].readAttribute("container");
if (container)
this.writeAttribute("container", container);
}
}
}
},
onBlur: function (event) {
if (this.delayedSearch)
window.clearTimeout(this.delayedSearch);
if (this.confirmedValue) {
this.value = this.confirmedValue;
if (this.readAttribute("container"))
this.fire("autocompletion:changedlist", this.readAttribute("container"));
else
this.fire("autocompletion:changed", event.keyCode);
}
else
this.writeAttribute("uid", null);
},
performSearch: function (input) {
// Perform address completion
if (document.contactLookupAjaxRequest) {
// Abort any pending request
document.contactLookupAjaxRequest.aborted = true;
document.contactLookupAjaxRequest.abort();
}
if (input.value.trim().length > minimumSearchLength) {
var urlstr = UserFolderURL + "Contacts/";
if (input.addressBook)
urlstr += input.addressBook + "/contact";
else
urlstr += "allContact";
urlstr += "Search?search=" + encodeURIComponent(input.value);
if (input.excludeGroups)
urlstr += "&excludeGroups=1";
if (input.excludeLists)
urlstr += "&excludeLists=1";
if (input.animationParent)
startAnimation(input.animationParent);
document.contactLookupAjaxRequest =
triggerAjaxRequest(urlstr, input.performSearchCallback.bind(input), input);
}
else {
if (document.currentPopupMenu)
hideMenu(document.currentPopupMenu);
}
},
performSearchCallback: function (http) {
if (http.readyState == 4) {
var list = this.menu.down("ul");
var input = http.callbackData;
if (http.status == 200) {
var start = input.value.length;
var data = http.responseText.evalJSON(true);
if (data.contacts.length > 1) {
list.select("li").each(function(item) {
item.stopObserving("mousedown");
item.remove();
});
// Populate popup menu
for (var i = 0; i < data.contacts.length; i++) {
var contact = data.contacts[i];
var completeEmail = contact["c_cn"];
var uid = "" + contact[this.uidField];
var c_name = "" + contact['c_name'];
if (contact["c_mail"])
completeEmail += " <" + contact["c_mail"] + ">";
var node = new Element('li', { 'address': completeEmail,
'uid': uid });
var matchPosition = completeEmail.toLowerCase().indexOf(data.searchText.toLowerCase());
if (matchPosition > -1) {
var matchBefore = completeEmail.substring(0, matchPosition);
var matchText = completeEmail.substring(matchPosition, matchPosition + data.searchText.length);
var matchAfter = completeEmail.substring(matchPosition + data.searchText.length);
node.appendChild(document.createTextNode(matchBefore));
node.appendChild(new Element('strong').update(matchText));
node.appendChild(document.createTextNode(matchAfter));
}
else {
node.appendChild(document.createTextNode(completeEmail));
}
list.appendChild(node);
if (c_name.endsWith(".vlf")) {
// Keep track of list containers
node.writeAttribute("container", contact['container']);
}
if (contact["contactInfo"])
node.appendChild(document.createTextNode(" (" + contact["contactInfo"] + ")"));
$(node).observe("mousedown", this.onAddressResultClick.bindAsEventListener(this));
}
// Show popup menu
var offsetScroll = Element.cumulativeScrollOffset(input);
var offset = Element.positionedOffset(input);
if ($(document.body).hasClassName("popup") && typeof initPopupMailer == 'undefined')
// Hack for some situations where the offset must be computed differently
offset = Element.cumulativeOffset(input);
var top = offset.top - offsetScroll.top + node.offsetHeight + 3;
var height = 'auto';
var heightDiff = window.height() - offset[1];
var nodeHeight = node.getHeight();
if ((data.contacts.length * nodeHeight) > heightDiff)
// Limit the size of the popup to the window height, minus 12 pixels
height = parseInt(heightDiff/nodeHeight) * nodeHeight - 12 + 'px';
this.menu.setStyle({ top: top + "px",
left: offset[0] + "px",
height: height,
maxWidth: (window.width() - offset[0] - 12) + "px",
visibility: "visible" });
this.menu.scrollTop = 0;
document.currentPopupMenu = this.menu;
$(document.body).stopObserving("click");
$(document.body).observe("click", onBodyClickMenuHandler);
}
else {
if (document.currentPopupMenu)
hideMenu(document.currentPopupMenu);
if (data.contacts.length == 1) {
// Single result
var contact = data.contacts[0];
var uid = "" + contact[this.uidField];
var c_name = "" + contact['c_name'];
input.writeAttribute("uid", uid);
if (c_name.endsWith(".vlf")) {
this.writeAttribute("container", contact['container']);
}
var completeEmail = contact["c_cn"];
if (contact["c_mail"])
completeEmail += " <" + contact["c_mail"] + ">";
if (contact["c_cn"].substring(0, input.value.length).toUpperCase()
== input.value.toUpperCase())
input.value = completeEmail;
else
// The result matches email address, not user name
input.value += ' >> ' + completeEmail;
input.confirmedValue = completeEmail;
var end = input.value.length;
$(input).selectText(start, end);
this.selectedIndex = -1;
}
}
}
else
if (document.currentPopupMenu)
hideMenu(document.currentPopupMenu);
document.contactLookupAjaxRequest = null;
}
},
onAddressResultClick: function(event) {
var e = Event.element(event);
if (e.tagName != 'LI')
e = e.up('LI');
if (e) {
preventDefault(event);
this.value = e.readAttribute("address");
this.writeAttribute("uid", e.readAttribute("uid"));
if (e.readAttribute("container"))
this.fire("autocompletion:changedlist", e.readAttribute("container"));
else {
this.confirmedValue = this.value;
this.fire("autocompletion:changed", Event.KEY_RETURN);
}
}
// Attributes that could be changed from the object
// inheriting the inteface
uidField: "c_name",
addressBook: null,
SOGoUsersSearch: false,
excludeGroups: false,
excludeLists: false,
// Internal attributes
animationParent: null,
selectedIndex: -1,
delay: 0.750,
delayedSearch: false,
menu: null,
bind: function () {
this.menu = $('contactsMenu');
this.writeAttribute("autocomplete", "off");
this.writeAttribute("container", null);
this.confirmedValue = null;
this.observe("keydown", this.onKeydown.bindAsEventListener(this));
this.observe("blur", this.onBlur.bindAsEventListener(this));
},
onKeydown: function (event) {
if (event.ctrlKey || event.metaKey) {
this.focussed = true;
return;
}
if (event.keyCode == Event.KEY_TAB) {
if (this.confirmedValue)
this.value = this.confirmedValue;
else
this.writeAttribute("uid", null);
if (document.currentPopupMenu)
hideMenu(document.currentPopupMenu);
}
else if (event.keyCode == 0
|| event.keyCode == Event.KEY_BACKSPACE
|| event.keyCode == Event.KEY_DELETE
|| event.keyCode == 32 // Space
|| event.keyCode > 47) {
this.confirmedValue = null;
this.selectedIndex = -1;
if (this.delayedSearch)
window.clearTimeout(this.delayedSearch);
this.delayedSearch = this.performSearch.delay(this.delay, this);
}
else if (event.keyCode == Event.KEY_RETURN) {
preventDefault(event);
if (this.confirmedValue)
this.value = this.confirmedValue;
else
this.writeAttribute("uid", null);
if (document.currentPopupMenu)
hideMenu(document.currentPopupMenu);
this.selectedIndex = -1;
if (this.readAttribute("container")) {
this.confirmedValue = null;
this.fire("autocompletion:changedlist", this.readAttribute("container"));
}
else
this.fire("autocompletion:changed", event.keyCode);
}
else if (this.menu.getStyle('visibility') == 'visible') {
if (event.keyCode == Event.KEY_UP) { // Up arrow
if (this.selectedIndex > 0) {
var contacts = this.menu.select("li");
contacts[this.selectedIndex--].removeClassName("selected");
this.value = contacts[this.selectedIndex].readAttribute("address");
this.confirmedValue = this.value;
this.writeAttribute("uid", contacts[this.selectedIndex].readAttribute("uid"));
contacts[this.selectedIndex].addClassName("selected");
var container = contacts[this.selectedIndex].readAttribute("container");
if (container)
this.writeAttribute("container", container);
}
}
else if (event.keyCode == Event.KEY_DOWN) { // Down arrow
var contacts = this.menu.select("li");
if (contacts.size() - 1 > this.selectedIndex) {
if (this.selectedIndex >= 0)
contacts[this.selectedIndex].removeClassName("selected");
this.selectedIndex++;
this.value = contacts[this.selectedIndex].readAttribute("address");
this.confirmedValue = this.value;
this.writeAttribute("uid", contacts[this.selectedIndex].readAttribute("uid"));
contacts[this.selectedIndex].addClassName("selected");
var container = contacts[this.selectedIndex].readAttribute("container");
if (container)
this.writeAttribute("container", container);
}
}
}
},
onBlur: function (event) {
if (this.delayedSearch)
window.clearTimeout(this.delayedSearch);
if (this.confirmedValue) {
this.value = this.confirmedValue;
if (this.readAttribute("container"))
this.fire("autocompletion:changedlist", this.readAttribute("container"));
else
this.fire("autocompletion:changed", event.keyCode);
}
else
this.writeAttribute("uid", null);
},
performSearch: function (input) {
// Perform address completion
if (document.contactLookupAjaxRequest) {
// Abort any pending request
document.contactLookupAjaxRequest.aborted = true;
document.contactLookupAjaxRequest.abort();
}
if (input.value.trim().length > minimumSearchLength) {
if (input.SOGoUsersSearch) {
var urlstr = UserFolderURL + "usersSearch?search=" + encodeURIComponent(input.value);
document.contactLookupAjaxRequest =
triggerAjaxRequest(urlstr, input.performUsersSearchCallback.bind(input), input);
}
else {
var urlstr = UserFolderURL + "Contacts/";
if (input.addressBook)
urlstr += input.addressBook + "/contact";
else
urlstr += "allContact";
urlstr += "Search?search=" + encodeURIComponent(input.value);
if (input.excludeGroups)
urlstr += "&excludeGroups=1";
if (input.excludeLists)
urlstr += "&excludeLists=1";
if (input.animationParent)
startAnimation(input.animationParent);
document.contactLookupAjaxRequest =
triggerAjaxRequest(urlstr, input.performSearchCallback.bind(input), input);
}
}
else {
if (document.currentPopupMenu)
hideMenu(document.currentPopupMenu);
}
},
performSearchCallback: function (http) {
if (http.readyState == 4) {
var list = this.menu.down("ul");
var input = http.callbackData;
if (http.status == 200) {
var start = input.value.length;
var data = http.responseText.evalJSON(true);
if (data.contacts.length > 1) {
list.select("li").each(function(item) {
item.stopObserving("mousedown");
item.remove();
});
// Populate popup menu
for (var i = 0; i < data.contacts.length; i++) {
var contact = data.contacts[i];
var completeEmail = contact["c_cn"];
var uid = "" + contact[this.uidField];
var c_name = "" + contact['c_name'];
if (contact["c_mail"])
completeEmail += " <" + contact["c_mail"] + ">";
var node = new Element('li', { 'address': completeEmail,
'uid': uid });
var matchPosition = completeEmail.toLowerCase().indexOf(data.searchText.toLowerCase());
if (matchPosition > -1) {
var matchBefore = completeEmail.substring(0, matchPosition);
var matchText = completeEmail.substring(matchPosition, matchPosition + data.searchText.length);
var matchAfter = completeEmail.substring(matchPosition + data.searchText.length);
node.appendChild(document.createTextNode(matchBefore));
node.appendChild(new Element('strong').update(matchText));
node.appendChild(document.createTextNode(matchAfter));
}
else {
node.appendChild(document.createTextNode(completeEmail));
}
list.appendChild(node);
if (c_name.endsWith(".vlf")) {
// Keep track of list containers
node.writeAttribute("container", contact['container']);
}
if (contact["contactInfo"])
node.appendChild(document.createTextNode(" (" + contact["contactInfo"] + ")"));
$(node).observe("mousedown", this.onAddressResultClick.bindAsEventListener(this));
}
// Show popup menu
var offsetScroll = Element.cumulativeScrollOffset(input);
var offset = Element.positionedOffset(input);
if ($(document.body).hasClassName("popup") && typeof initPopupMailer == 'undefined')
// Hack for some situations where the offset must be computed differently
offset = Element.cumulativeOffset(input);
var top = offset.top - offsetScroll.top + node.offsetHeight + 3;
var height = 'auto';
var heightDiff = window.height() - offset[1];
var nodeHeight = node.getHeight();
if ((data.contacts.length * nodeHeight) > heightDiff)
// Limit the size of the popup to the window height, minus 12 pixels
height = parseInt(heightDiff/nodeHeight) * nodeHeight - 12 + 'px';
this.menu.setStyle({ top: top + "px",
left: offset[0] + "px",
height: height,
maxWidth: (window.width() - offset[0] - 12) + "px",
visibility: "visible" });
this.menu.scrollTop = 0;
document.currentPopupMenu = this.menu;
$(document.body).stopObserving("click");
$(document.body).observe("click", onBodyClickMenuHandler);
}
else {
if (document.currentPopupMenu)
hideMenu(document.currentPopupMenu);
if (data.contacts.length == 1) {
// Single result
var contact = data.contacts[0];
var uid = "" + contact[this.uidField];
var c_name = "" + contact['c_name'];
input.writeAttribute("uid", uid);
if (c_name.endsWith(".vlf")) {
this.writeAttribute("container", contact['container']);
}
var completeEmail = contact["c_cn"];
if (contact["c_mail"])
completeEmail += " <" + contact["c_mail"] + ">";
if (contact["c_cn"].substring(0, input.value.length).toUpperCase()
== input.value.toUpperCase())
input.value = completeEmail;
else
// The result matches email address, not user name
input.value += ' >> ' + completeEmail;
input.confirmedValue = completeEmail;
var end = input.value.length;
$(input).selectText(start, end);
this.selectedIndex = -1;
}
}
}
else
if (document.currentPopupMenu)
hideMenu(document.currentPopupMenu);
document.contactLookupAjaxRequest = null;
}
},
performUsersSearchCallback: function (http) {
if (http.readyState == 4) {
var list = this.menu.down("ul");
var input = http.callbackData;
if (http.status == 200) {
var response = http.responseText.evalJSON();
if (response.length > 1) {
list.select("li").each(function(item) {
item.stopObserving("mousedown");
item.remove();
});
// Populate popup menu
for (var i = 0; i < response.length; i++) {
var c_name = response[i][1];
var completeEmail = c_name;
var c_mail = response[i][2];
var uid = response[i][3];
if (c_mail)
completeEmail += " <" + c_mail + ">";
var node = new Element('li', { 'address': completeEmail,
'uid': uid });
var matchPosition = completeEmail.toLowerCase().indexOf(input.getValue().toLowerCase());
if (matchPosition > -1) {
var matchBefore = completeEmail.substring(0, matchPosition);
var matchText = completeEmail.substring(matchPosition, matchPosition + input.getValue().length);
var matchAfter = completeEmail.substring(matchPosition + input.getValue().length);
node.appendChild(document.createTextNode(matchBefore));
node.appendChild(new Element('strong').update(matchText));
node.appendChild(document.createTextNode(matchAfter));
}
else {
node.appendChild(document.createTextNode(completeEmail));
}
list.appendChild(node);
$(node).observe("mousedown", this.onAddressResultClick.bindAsEventListener(this));
}
// Show popup menu
var offsetScroll = Element.cumulativeScrollOffset(input);
var offset = Element.positionedOffset(input);
if ($(document.body).hasClassName("popup") && typeof initPopupMailer == 'undefined')
// Hack for some situations where the offset must be computed differently
offset = Element.cumulativeOffset(input);
var top = offset.top - offsetScroll.top + node.offsetHeight + 3;
var height = 'auto';
var heightDiff = window.height() - offset[1];
var nodeHeight = node.getHeight();
if ((response.length * nodeHeight) > heightDiff)
// Limit the size of the popup to the window height, minus 12 pixels
height = parseInt(heightDiff/nodeHeight) * nodeHeight - 12 + 'px';
this.menu.setStyle({ top: top + "px",
left: offset[0] + "px",
height: height,
maxWidth: (window.width() - offset[0] - 12) + "px",
visibility: "visible" });
this.menu.scrollTop = 0;
document.currentPopupMenu = this.menu;
$(document.body).stopObserving("click");
$(document.body).observe("click", onBodyClickMenuHandler);
}
else {
if (document.currentPopupMenu)
hideMenu(document.currentPopupMenu);
if (response.length == 1) {
// Single result
var c_name = response[0][1];
var completeEmail = c_name;
var c_mail = response[0][2];
var c_uid = response[0][0];
input.writeAttribute("uid", c_uid);
if (c_mail)
completeEmail += " <" + c_mail + ">";
if (c_uid.substring(0, input.getValue().length).toUpperCase() == input.getValue().toUpperCase())
input.value = completeEmail;
else
// The result matches email address, not user name
input.value += ' >> ' + completeEmail;
input.confirmedValue = completeEmail;
var end = input.getValue().length;
$(input).selectText(start, end);
this.selectedIndex = -1;
}
}
}
else
if (document.currentPopupMenu)
hideMenu(document.currentPopupMenu);
document.contactLookupAjaxRequest = null;
}
},
onAddressResultClick: function(event) {
var e = Event.element(event);
if (e.tagName != 'LI')
e = e.up('LI');
if (e) {
preventDefault(event);
this.value = e.readAttribute("address");
this.writeAttribute("uid", e.readAttribute("uid"));
if (e.readAttribute("container"))
this.fire("autocompletion:changedlist", e.readAttribute("container"));
else {
this.confirmedValue = this.value;
this.fire("autocompletion:changed", Event.KEY_RETURN);
}
}
}
};

View File

@ -14,6 +14,12 @@ DIV.bottomToolbar
right: 2em;
bottom: 8px; }
#WhiteListAdd, #WhiteListDelete
{
border-bottom: 1px solid #9B9B9B;
border-right: 1px solid #9B9B9B;
}
#mailAccountsToolbar
{ left: 5px;
bottom: 9px;
@ -47,17 +53,35 @@ DIV.listWrapper
padding: 0px;
margin-top: 2px;
border-left: 1px solid #9b9b9b;
border-right: 1px solid #9b9b9b;
background: #ccddec;}
.listWrapper TABLE TD
{ height: 22px; }
#calendarCategoriesListWrapper
{ top: 232px;
{ top:1em;
bottom: 30px;
right: 2em;
left: 2em; }
#appointmentsWhiteListWrapper
{ top:4.5em;
bottom: 30px;
right: 2em;
left: 2em; }
#tableViewWhiteList
{ width:100%; }
DIV#calendarOptionsTabs
{ position: absolute;
top: 225px;
left: 0px;
right: 0px;
bottom: 0px;
}
#contactsCategoriesListWrapper
{ overflow: auto;
position: absolute;

View File

@ -3,109 +3,112 @@ var mailAccounts = null;
var dialogs = {};
function savePreferences(sender) {
var sendForm = true;
var sigList = $("signaturePlacementList");
if (sigList)
sigList.disabled = false;
if ($("calendarCategoriesListWrapper"))
serializeCalendarCategories();
if ($("contactsCategoriesListWrapper"))
serializeContactsCategories();
if ($("mailLabelsListWrapper"))
serializeMailLabels();
if (typeof mailCustomFromEnabled !== "undefined" && !emailRE.test($("email").value)) {
showAlertDialog(_("Please specify a valid sender address."));
sendForm = false;
}
if ($("replyTo")) {
var replyTo = $("replyTo").value;
if (!replyTo.blank() && !emailRE.test(replyTo)) {
showAlertDialog(_("Please specify a valid reply-to address."));
sendForm = false;
}
}
if ($("dayStartTime")) {
var start = $("dayStartTime");
var selectedStart = parseInt(start.options[start.selectedIndex].value);
var end = $("dayEndTime");
var selectedEnd = parseInt(end.options[end.selectedIndex].value);
var sendForm = true;
if (selectedStart >= selectedEnd) {
showAlertDialog (_("Day start time must be prior to day end time."));
sendForm = false;
}
}
if ($("enableVacation") && $("enableVacation").checked) {
if ($("autoReplyText").value.strip().length == 0 || $("autoReplyEmailAddresses").value.strip().length == 0) {
showAlertDialog(_("Please specify your message and your email addresses for which you want to enable auto reply."));
sendForm = false;
}
var sigList = $("signaturePlacementList");
if (sigList)
sigList.disabled = false;
if ($("autoReplyText").value.strip().endsWith('\n.')) {
showAlertDialog(_("Your vacation message must not end with a single dot on a line."));
sendForm = false;
}
if ($("appointmentsWhiteListWrapper"))
serializeAppointmentsWhiteList();
if ($("enableVacationEndDate") && $("enableVacationEndDate").checked) {
var e = $("vacationEndDate_date");
var endDate = e.inputAsDate();
var now = new Date();
if (isNaN(endDate.getTime()) || endDate.getTime() < now.getTime()) {
showAlertDialog(_("End date of your auto reply must be in the future."));
if ($("calendarCategoriesListWrapper"))
serializeCalendarCategories();
if ($("contactsCategoriesListWrapper"))
serializeContactsCategories();
if ($("mailLabelsListWrapper"))
serializeMailLabels();
if (typeof mailCustomFromEnabled !== "undefined" && !emailRE.test($("email").value)) {
showAlertDialog(_("Please specify a valid sender address."));
sendForm = false;
}
}
}
if ($("enableForward") && $("enableForward").checked) {
var addresses = $("forwardAddress").value.split(",");
for (var i = 0; i < addresses.length && sendForm; i++)
if (!emailRE.test(addresses[i].strip())) {
showAlertDialog(_("Please specify an address to which you want to forward your messages."));
sendForm = false;
}
}
if (typeof sieveCapabilities != "undefined") {
var jsonFilters = prototypeIfyFilters();
$("sieveFilters").setValue(Object.toJSON(jsonFilters));
}
if (sendForm) {
saveMailAccounts();
triggerAjaxRequest($("mainForm").readAttribute("action"), function (http) {
if (http.readyState == 4) {
var response = http.responseText.evalJSON(true);
if (http.status == 503) {
showAlertDialog(_(response.textStatus));
if ($("replyTo")) {
var replyTo = $("replyTo").value;
if (!replyTo.blank() && !emailRE.test(replyTo)) {
showAlertDialog(_("Please specify a valid reply-to address."));
sendForm = false;
}
else if (http.status == 200) {
if (response.hasChanged == 1) {
window.opener.location.reload();
window.close();
}
else {
window.close();
}
}
if ($("dayStartTime")) {
var start = $("dayStartTime");
var selectedStart = parseInt(start.options[start.selectedIndex].value);
var end = $("dayEndTime");
var selectedEnd = parseInt(end.options[end.selectedIndex].value);
if (selectedStart >= selectedEnd) {
showAlertDialog (_("Day start time must be prior to day end time."));
sendForm = false;
}
else {
showAlertDialog(_(response.textStatus));
}
if ($("enableVacation") && $("enableVacation").checked) {
if ($("autoReplyText").value.strip().length == 0 || $("autoReplyEmailAddresses").value.strip().length == 0) {
showAlertDialog(_("Please specify your message and your email addresses for which you want to enable auto reply."));
sendForm = false;
}
}
},
null,
Form.serialize($("mainForm")), // excludes the file input
{ "Content-type": "application/x-www-form-urlencoded"}
);
if ($("autoReplyText").value.strip().endsWith('\n.')) {
showAlertDialog(_("Your vacation message must not end with a single dot on a line."));
sendForm = false;
}
if ($("enableVacationEndDate") && $("enableVacationEndDate").checked) {
var e = $("vacationEndDate_date");
var endDate = e.inputAsDate();
var now = new Date();
if (isNaN(endDate.getTime()) || endDate.getTime() < now.getTime()) {
showAlertDialog(_("End date of your auto reply must be in the future."));
sendForm = false;
}
}
}
if ($("enableForward") && $("enableForward").checked) {
var addresses = $("forwardAddress").value.split(",");
for (var i = 0; i < addresses.length && sendForm; i++)
if (!emailRE.test(addresses[i].strip())) {
showAlertDialog(_("Please specify an address to which you want to forward your messages."));
sendForm = false;
}
}
if (typeof sieveCapabilities != "undefined") {
var jsonFilters = prototypeIfyFilters();
$("sieveFilters").setValue(Object.toJSON(jsonFilters));
}
if (sendForm) {
saveMailAccounts();
triggerAjaxRequest($("mainForm").readAttribute("action"), function (http) {
if (http.readyState == 4) {
var response = http.responseText.evalJSON(true);
if (http.status == 503) {
showAlertDialog(_(response.textStatus));
}
else if (http.status == 200) {
if (response.hasChanged == 1) {
window.opener.location.reload();
window.close();
}
else {
window.close();
}
}
else {
showAlertDialog(_(response.textStatus));
}
}
},
null,
Form.serialize($("mainForm")), // excludes the file input
{ "Content-type": "application/x-www-form-urlencoded"}
);
}
return false;
}
@ -118,14 +121,14 @@ function prototypeIfyFilters() {
newFilter.name = filter.name;
newFilter.match = filter.match;
newFilter.active = filter.active;
if (filter.rules) {
newFilter.rules = $([]);
for (var j = 0; j < filter.rules.length; j++) {
newFilter.rules.push($(filter.rules[j]));
}
}
if (filter.actions) {
newFilter.actions = $([]);
for (var j = 0; j < filter.actions.length; j++) {
@ -134,7 +137,7 @@ function prototypeIfyFilters() {
}
newFilters.push(newFilter);
}
return newFilters;
}
@ -204,25 +207,76 @@ function initPreferences() {
var tabsContainer = $("preferencesTabs");
var controller = new SOGoTabsController();
controller.attachToTabsContainer(tabsContainer);
// Inner tabs on the mail module tab
tabsContainer = $('mailOptionsTabs');
if (tabsContainer) {
var mailController = new SOGoTabsController();
mailController.attachToTabsContainer(tabsContainer);
}
// Inner tabs on the calendar module tab
tabsContainer = $('calendarOptionsTabs');
if (tabsContainer) {
var mailController = new SOGoTabsController();
mailController.attachToTabsContainer(tabsContainer);
}
_setupEvents();
// Optional function called when initializing the preferences
// Typically defined inline in the UIxAdditionalPreferences.wox template
if (typeof (initAdditionalPreferences) != "undefined")
initAdditionalPreferences();
// Color picker
$('colorPickerDialog').on('click', 'span', onColorPickerChoice);
$(document.body).on("click", onBodyClickHandler);
// Calendar whiteList
var whiteList = $("appointmentsWhiteListWrapper");
if(whiteList) {
var whiteListValue = $("whiteList").getValue();
if (whiteListValue != "") {
whiteListValue = whiteListValue.split(",");
var tablebody = $("appointmentsWhiteListWrapper").childNodesWithTag("table")[0].tBodies[0];
for (i = 0; i < whiteListValue.length; i++)
{
var elements = whiteListValue[i].split("=");
var row = new Element("tr");
var td = new Element("td").update("");
var textField = new Element("input");
var span = new Element("span");
row.addClassName("whiteListRow");
row.observe("mousedown", onRowClick);
td.addClassName ("whiteListCell");
td.observe("mousedown", endAllEditables);
td.observe("dblclick", onNameEdit);
textField.addInterface(SOGoAutoCompletionInterface);
textField.SOGoUsersSearch = true;
textField.observe("autocompletion:changed", endEditable);
textField.addClassName("textField");
textField.value = elements[1];
textField.setAttribute("uid", elements[0]);
textField.hide();
span.innerText = elements[1];
td.appendChild(textField);
td.appendChild(span);
row.appendChild (td);
tablebody.appendChild(row);
$(tablebody).deselectAll();
}
}
var table = whiteList.childNodesWithTag("table")[0];
table.multiselect = true;
$("appointmentsWhiteListAdd").observe("click", onAppointmentsWhiteListAdd);
$("appointmentsWhiteListDelete").observe("click", onAppointmentsWhiteListDelete);
}
// Calender categories
var wrapper = $("calendarCategoriesListWrapper");
if (wrapper) {
@ -237,7 +291,7 @@ function initPreferences() {
$("calendarCategoryDelete").observe("click", onCalendarCategoryDelete);
wrapper.observe("scroll", onBodyClickHandler);
}
// Mail labels/tags
var wrapper = $("mailLabelsListWrapper");
if (wrapper) {
@ -251,7 +305,7 @@ function initPreferences() {
$("mailLabelAdd").observe("click", onMailLabelAdd);
$("mailLabelDelete").observe("click", onMailLabelDelete);
}
// Contact categories
wrapper = $("contactsCategoriesListWrapper");
if (wrapper) {
@ -264,32 +318,31 @@ function initPreferences() {
$("contactsCategoryAdd").observe("click", onContactsCategoryAdd);
$("contactsCategoryDelete").observe("click", onContactsCategoryDelete);
}
if ($("replyPlacementList"))
onReplyPlacementListChange();
var button = $("addDefaultEmailAddresses");
if (button)
button.observe("click", addDefaultEmailAddresses);
button = $("changePasswordBtn");
if (button)
button.observe("click", onChangePasswordClick);
initSieveFilters();
initMailAccounts();
button = $("enableVacationEndDate");
if (button) {
jQuery("#vacationEndDate_date").closest(".date").datepicker(
{ autoclose: true, position: 'above', weekStart: $('weekStartDay').getValue() });
jQuery("#vacationEndDate_date").closest(".date").datepicker({ autoclose: true, position: 'above', weekStart: $('weekStartDay').getValue() });
button.on("click", function(event) {
if (this.checked)
$("vacationEndDate_date").enable();
else
$("vacationEndDate_date").disable();
});
if (this.checked)
$("vacationEndDate_date").enable();
else
$("vacationEndDate_date").disable();
});
}
onAddOutgoingAddressesCheck();
}
@ -977,6 +1030,119 @@ function onCalendarColorEdit(e) {
onCCE(e, "calendarCategoriesListWrapper");
}
function makeEditable (element) {
element.addClassName("editing");
element.removeClassName("whiteListCell");
var span = element.down("SPAN");
span.update();
var textField = element.down("INPUT");
textField.show();
textField.focus();
textField.select();
return true;
}
function endAllEditables (e) {
var r = $$("TABLE#tableViewWhiteList TBODY TR TD");
for (var i = 0; i < r.length; i++) {
var element = $(r[i]);
if (r[i] != this && element.hasClassName("editing"))
endEditable(null, element.down("INPUT"));
}
}
function onNameEdit (e) {
endAllEditables();
if (!this.hasClassName("editing")) {
makeEditable (this);
}
}
function endEditable(event, textField) {
if (!textField)
textField = this;
var uid = textField.readAttribute("uid");
var cell = textField.up("TD");
var textSpan = cell.down("SPAN");
cell.removeClassName("editing");
cell.addClassName("whiteListCell");
textField.hide();
var tmp = textField.value;
tmp = tmp.replace (/</, "&lt;");
tmp = tmp.replace (/>/, "&gt;");
if (!uid)
cell.up("TR").addClassName("notfound");
if (tmp)
textSpan.update(tmp);
else
cell.up("TR").remove();
if (event)
Event.stop(event);
return false;
}
function onAppointmentsWhiteListAdd(e) {
var tablebody = $("appointmentsWhiteListWrapper").childNodesWithTag("table")[0].tBodies[0];
var row = new Element("tr");
var td = new Element("td").update("");
var textField = new Element("input");
var span = new Element("span");
row.addClassName("whiteListRow");
row.observe("mousedown", onRowClick);
td.addClassName ("whiteListCell");
td.observe("mousedown", endAllEditables);
td.observe("dblclick", onNameEdit);
textField.addInterface(SOGoAutoCompletionInterface);
textField.SOGoUsersSearch = true;
textField.observe("autocompletion:changed", endEditable);
textField.addClassName("textField");
td.appendChild(textField);
td.appendChild(span);
row.appendChild (td);
tablebody.appendChild(row);
$(tablebody).deselectAll();
row.selectElement();
makeEditable(td);
}
function onAppointmentsWhiteListDelete(e) {
var list = $('appointmentsWhiteListWrapper').down("TABLE").down("TBODY");
var rows = list.getSelectedNodes();
var count = rows.length;
for (var i=0; i < count; i++) {
rows[i].editionController = null;
rows[i].remove();
}
}
function serializeAppointmentsWhiteList() {
var r = $$("#appointmentsWhiteListWrapper TBODY TR");
var values = [];
for (var i = 0; i < r.length; i++) {
var tds = r[i].childElements().first().down("INPUT");
var uid = tds.getAttribute("uid");
var value = tds.getValue();
var user = uid + "=" + value;
if (uid != null)
values.push(user);
}
$("whiteList").value = values;
}
function onCalendarCategoryAdd(e) {
var row = new Element("tr");
var nametd = new Element("td").update("");
@ -1016,7 +1182,7 @@ function serializeCalendarCategories() {
var values = [];
for (var i = 0; i < r.length; i++) {
var tds = r[i].childElements();
var name = $(tds.first()).innerHTML;
var name = $(tds.first()).innerHTML.trim();
var color = $(tds.last().childElements().first()).readAttribute('data-color');
values.push("\"" + name + "\": \"" + color + "\"");
}
@ -1144,7 +1310,7 @@ function onContactsCategoryAdd(e) {
var list = $('contactsCategoriesListWrapper').down("TABLE").down("TBODY");
list.appendChild(row);
resetContactsTableActions ();
resetContactsTableActions();
nametd.editionController.startEditing();
}
@ -1175,11 +1341,10 @@ function serializeContactsCategories() {
/* / contact categories */
function onAddOutgoingAddressesCheck(checkBox) {
if (!checkBox) {
checkBox = $("addOutgoingAddresses");
}
$("addressBookList").disabled = !checkBox.checked;
if (!checkBox) {
checkBox = $("addOutgoingAddresses");
}
$("addressBookList").disabled = !checkBox.checked;
}
function onReplyPlacementListChange() {

View File

@ -374,7 +374,7 @@ TH.tbtv_navcell
text-align: left;
font-weight: normal;
background-color: #E7E7E7;
height: 20px; }
height: 20px;}
TD.sortableTableHeader:active,
TH.sortableTableHeader:active
@ -410,7 +410,8 @@ TH.tbtv_headercell IMG.tbtv_sortcell
text-align: right;
border: 0px;
width: 12px;
height: 12px; }
height: 12px;
top:0;}
.tableview
{ cursor: default;