(js) New file structure for Angular modules
JavaScript files are now merged by the 'js' Grunt task.pull/91/head
parent
b1ff1d4365
commit
1dc5f0d412
|
@ -6,7 +6,7 @@
|
|||
xmlns:const="http://www.skyrix.com/od/constant"
|
||||
xmlns:label="OGo:label"
|
||||
const:userDefaultsKeys="SOGoContactsCategories"
|
||||
const:jsFiles="Common/user-model.js, Common/acl-model.js, Common/resource.js, Contacts/card-model.js, Contacts/addressbook-model.js"
|
||||
const:jsFiles="Contacts.app.js, Contacts.js, Common.js, Contacts.js"
|
||||
className="UIxPageFrame"
|
||||
title="name">
|
||||
<script type="text/javascript">
|
||||
|
@ -319,7 +319,7 @@
|
|||
|
||||
<md-button class="iconButton md-fab md-fab-bottom-right md-accent"
|
||||
label:aria-label="New Contact"
|
||||
ng-click="newComponent()">
|
||||
ng-click="newComponent($event)">
|
||||
<i class="md-icon-add"><!--icon--></i>
|
||||
</md-button>
|
||||
</div>
|
||||
|
|
|
@ -8,44 +8,44 @@
|
|||
xmlns:uix="OGo:uix">
|
||||
<md-dialog flex="50" flex-sm="100">
|
||||
<md-dialog-content>
|
||||
<md-input-container md-no-float="md-no-float" layout="row">
|
||||
<i class="md-icon-search"><!--icon--></i>
|
||||
<input ng-model="searchString" type="text" placeholder="Name" sg-user-typeahead="sg-user-typeahead"/>
|
||||
<h2 class="md-headline"><var:string label:value="Subscribe"/></h2>
|
||||
<md-input-container>
|
||||
<label><i class="md-icon-search"><!--icon--></i><var:string label:value="Search"/></label>
|
||||
<input type="input"
|
||||
autocomplete="off"
|
||||
ng-model="vm.searchText"
|
||||
ng-model-options="vm.searchTextOptions"
|
||||
ng-change="vm.onChange()"/>
|
||||
</md-input-container>
|
||||
<md-list>
|
||||
<md-list-item
|
||||
layout="column"
|
||||
ng-repeat="user in users">
|
||||
<md-button class="sg-expandable" ng-click="selectUser($index)">
|
||||
<div layout="row" layout-align="space-between center"
|
||||
<md-list-item layout="column"
|
||||
ng-repeat="user in vm.users">
|
||||
<md-button class="sg-expandable" ng-click="vm.selectUser($index)">
|
||||
<div layout="row" layout-align="start center"
|
||||
layout-fill="true">
|
||||
<div class="sg-avatar"><!-- normal-user --></div>
|
||||
<span class="sg-item-name">{{user.$shortFormat()}}</span>
|
||||
<span class="md-display-1">
|
||||
<i class="md-icon-expand-more"
|
||||
ng-show="user.uid != selectedUser.uid"><!--icon--></i>
|
||||
<i class="md-icon-expand-less"
|
||||
ng-show="user.uid == selectedUser.uid"><!--icon--></i>
|
||||
<span class="md-secondary md-display-1">
|
||||
<i ng-class="{ 'md-icon-expand-more': user.uid != vm.selectedUser.uid,
|
||||
'md-icon-expand-less': user.uid == vm.selectedUser.uid }"><!--icon--></i>
|
||||
</span>
|
||||
</div>
|
||||
</md-button>
|
||||
<md-list layout-fill="true" ng-if="user.uid == selectedUser.uid">
|
||||
<md-list layout-fill="true"
|
||||
ng-show="user == vm.selectedUser">
|
||||
<md-list-item ng-show="user.$$folders.length == 0">
|
||||
<i class="md-icon-warning"><!-- no subscription --></i>
|
||||
<var:string label:value="No possible subscription"/>
|
||||
</md-list-item>
|
||||
<md-list-item
|
||||
layout="row"
|
||||
layout-fill="true"
|
||||
ng-repeat="folder in user.$$folders">
|
||||
<i class="md-icon-contacts md-padding"
|
||||
ng-show="folder.type == 'Contact'"><!--icon--></i>
|
||||
<i class="md-icon-today md-padding"
|
||||
ng-show="folder.type == 'Appointment'"><!--icon--></i>
|
||||
<md-list-item layout="row" layout-fill="true"
|
||||
ng-repeat="folder in user.$$folders">
|
||||
<i class="md-padding"
|
||||
ng-class="{ 'md-icon-contacts': folder.type == 'Contact',
|
||||
'md-icon-today': folder.type == 'Appointment' }"><!--icon--></i>
|
||||
<p class="md-flex sg-item-name">{{folder.displayName}}</p>
|
||||
<md-button
|
||||
class="md-raised"
|
||||
ng-click="selectFolder(folder)">Subscribe</md-button>
|
||||
ng-click="vm.selectFolder(folder)"><var:string label:value="Subscribe"/></md-button>
|
||||
</md-list-item>
|
||||
</md-list>
|
||||
<md-divider ng-if="!$last"><!-- divider --></md-divider>
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
title="title"
|
||||
const:userDefaultsKeys="SOGoMailMessageCheck,SOGoRefreshViewCheck,SOGoMailSortByThreads,SOGoMailListViewColumnsOrder,SOGoMailDisplayRemoteInlineImages,SOGoMailComposeMessageType,SOGoMailReplyPlacement,SOGoMailLabelsColors"
|
||||
const:userSettingsKeys="Mail"
|
||||
const:jsFiles="Common/resource.js, Common/user-model.js, Common/acl-model.js, Contacts/card-model.js, Contacts/addressbook-model.js, Mailer/message-model.js, Mailer/mailbox-model.js, Mailer/account-model.js, vendor/ckeditor/ckeditor.js, vendor/ckeditor/ck.js, vendor/angular-file-upload.js">
|
||||
const:jsFiles="Mailer.app.js, Common.js, Contacts.js, Mailer.js, vendor/ckeditor/ckeditor.js, vendor/ckeditor/ck.js, vendor/angular-file-upload.js">
|
||||
<script type="text/javascript">
|
||||
var mailAccounts =<var:string value="mailAccounts" const:escapeHTML="NO" />;
|
||||
var userNames =<var:string value="userNames" const:escapeHTML="NO" />;
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
xmlns:label="OGo:label"
|
||||
className="UIxPageFrame"
|
||||
title="title"
|
||||
const:jsFiles="Common/resource.js,Common/SOGoAuthentication.js,Mailer/mailbox-model.js,Mailer/message-model.js,Preferences/preferences-model.js,Common/user-model.js">
|
||||
const:jsFiles="Preferences.app.js, Common.js, Mailer.js, Preferences.js">
|
||||
|
||||
<main class="view md-layout-fill" ui-view="preferences" layout="row"
|
||||
ng-controller="navController"><!-- preferences --> </main>
|
||||
|
@ -59,7 +59,7 @@
|
|||
</md-toolbar>
|
||||
|
||||
<form name="preferencesForm"
|
||||
ng-submit="save()">
|
||||
ng-submit="app.save()">
|
||||
<div ui-view="module"><!-- view --></div>
|
||||
<md-button class="" type="submit">
|
||||
<var:string label:value="Save" />
|
||||
|
@ -89,7 +89,7 @@
|
|||
<div layout="row" layout-align="space-around center">
|
||||
<div><var:string label:value="Language :"/></div>
|
||||
<div>
|
||||
<md-select ng-model="preferences.defaults.SOGoLanguage">
|
||||
<md-select ng-model="app.preferences.defaults.SOGoLanguage">
|
||||
<var:foreach list="languages" item="item">
|
||||
<md-option var:value="item">
|
||||
<var:string value="languageText"/>
|
||||
|
@ -102,7 +102,7 @@
|
|||
<div layout="row" layout-align="space-around center">
|
||||
<div><var:string label:value="Current Time Zone :"/></div>
|
||||
<div>
|
||||
<md-select ng-model="preferences.defaults.SOGoTimeZone">
|
||||
<md-select ng-model="app.preferences.defaults.SOGoTimeZone">
|
||||
<var:foreach list="timeZonesList" item="item">
|
||||
<md-option var:value="item">
|
||||
<var:string value="item"/>
|
||||
|
@ -115,7 +115,7 @@
|
|||
<div layout="row" layout-align="space-around center">
|
||||
<div><var:string label:value="Short Date Format :"/></div>
|
||||
<div>
|
||||
<md-select ng-model="preferences.defaults.SOGoShortDateFormat">
|
||||
<md-select ng-model="app.preferences.defaults.SOGoShortDateFormat">
|
||||
<var:foreach list="shortDateFormatsList" item="item">
|
||||
<md-option var:value="item">
|
||||
<var:string value="itemShortDateFormatText"/>
|
||||
|
@ -134,7 +134,7 @@
|
|||
<div layout="row" layout-align="space-around center">
|
||||
<div><var:string label:value="Long Date Format :"/></div>
|
||||
<div>
|
||||
<md-select ng-model="preferences.defaults.SOGoLongDateFormat">
|
||||
<md-select ng-model="app.preferences.defaults.SOGoLongDateFormat">
|
||||
<var:foreach list="longDateFormatsList" item="item">
|
||||
<md-option var:value="item">
|
||||
<var:string value="itemLongDateFormatText"/>
|
||||
|
@ -152,7 +152,7 @@
|
|||
<div layout="row" layout-align="space-around center">
|
||||
<div><var:string label:value="Time Format :"/></div>
|
||||
<div>
|
||||
<md-select ng-model="preferences.defaults.SOGoTimeFormat">
|
||||
<md-select ng-model="app.preferences.defaults.SOGoTimeFormat">
|
||||
<var:foreach list="timeFormatsList" item="item">
|
||||
<md-option var:value="item">
|
||||
<var:string value="itemTimeFormatText"/>
|
||||
|
@ -169,7 +169,7 @@
|
|||
|
||||
<div layout="row" layout-align="space-around center">
|
||||
<div><var:string label:value="Default Module:"/></div>
|
||||
<md-select ng-model="preferences.defaults.SOGoLoginModule">
|
||||
<md-select ng-model="app.preferences.defaults.SOGoLoginModule">
|
||||
<var:foreach list="availableModules" item="item">
|
||||
<md-option var:value="item">
|
||||
<var:string value="itemModuleText"/>
|
||||
|
@ -181,7 +181,7 @@
|
|||
<div layout="row" layout-align="space-around center">
|
||||
<div><var:string label:value="Refresh View :"/></div>
|
||||
<div>
|
||||
<md-select ng-model="preferences.defaults.SOGoRefreshViewCheck">
|
||||
<md-select ng-model="app.preferences.defaults.SOGoRefreshViewCheck">
|
||||
<var:foreach list="refreshViewList" item="item">
|
||||
<md-option var:value="item">
|
||||
<var:string value="itemRefreshViewCheckText"/>
|
||||
|
@ -243,7 +243,7 @@
|
|||
<div layout="row" layout-align="space-around center">
|
||||
<div><var:string label:value="Week begins on :" /></div>
|
||||
<div>
|
||||
<md-select ng-model="preferences.defaults.SOGoFirstDayOfWeek">
|
||||
<md-select ng-model="app.preferences.defaults.SOGoFirstDayOfWeek">
|
||||
<var:foreach list="daysList" item="item">
|
||||
<md-option var:value="item">
|
||||
<var:string value="itemWeekStartDay"/>
|
||||
|
@ -261,7 +261,7 @@
|
|||
<div layout="row" layout-align="space-around center">
|
||||
<div><var:string label:value="Day start time :" /></div>
|
||||
<div>
|
||||
<md-select ng-model="preferences.defaults.SOGoDayStartTime">
|
||||
<md-select ng-model="app.preferences.defaults.SOGoDayStartTime">
|
||||
<var:foreach list="hoursList" item="item">
|
||||
<md-option var:value="item">
|
||||
<var:string value="item"/>
|
||||
|
@ -279,7 +279,7 @@
|
|||
<div layout="row" layout-align="space-around center">
|
||||
<div><var:string label:value="Day end time :" /></div>
|
||||
<div>
|
||||
<md-select ng-model="preferences.defaults.SOGoDayEndTime">
|
||||
<md-select ng-model="app.preferences.defaults.SOGoDayEndTime">
|
||||
<var:foreach list="hoursList" item="item">
|
||||
<md-option var:value="item">
|
||||
<var:string value="item"/>
|
||||
|
@ -296,7 +296,7 @@
|
|||
|
||||
<div layout="row" layout-align="space-around center">
|
||||
<md-checkbox
|
||||
ng-model="preferences.defaults.SOGoBusyOffHours"
|
||||
ng-model="app.preferences.defaults.SOGoBusyOffHours"
|
||||
ng-true-value="1"
|
||||
ng-false-value="0">
|
||||
<var:string label:value="Show time as busy outside working hours"/>
|
||||
|
@ -306,7 +306,7 @@
|
|||
<div layout="row" layout-align="space-around center">
|
||||
<div><var:string label:value="First week of year :"/></div>
|
||||
<div>
|
||||
<md-select ng-model="preferences.defaults.SOGoFirstWeekOfYear">
|
||||
<md-select ng-model="app.preferences.defaults.SOGoFirstWeekOfYear">
|
||||
<var:foreach list="firstWeekList" item="item">
|
||||
<md-option var:value="item">
|
||||
<var:string value="itemFirstWeekText"/>
|
||||
|
@ -324,7 +324,7 @@
|
|||
<div layout="row" layout-align="space-around center">
|
||||
<div><var:string label:value="Default calendar :" /></div>
|
||||
<div>
|
||||
<md-select ng-model="preferences.defaults.SOGoDefaultCalendar">
|
||||
<md-select ng-model="app.preferences.defaults.SOGoDefaultCalendar">
|
||||
<var:foreach list="defaultCalendarList" item="item">
|
||||
<md-option var:value="item">
|
||||
<var:string value="itemCalendarText"/>
|
||||
|
@ -342,7 +342,7 @@
|
|||
<div layout="row" layout-align="space-around center">
|
||||
<div><var:string label:value="Default events classification :" /></div>
|
||||
<div>
|
||||
<md-select ng-model="preferences.defaults.SOGoCalendarEventsDefaultClassification">
|
||||
<md-select ng-model="app.preferences.defaults.SOGoCalendarEventsDefaultClassification">
|
||||
<var:foreach list="calendarClassificationsList" item="item">
|
||||
<md-option var:value="item">
|
||||
<var:string value="itemClassificationText"/>
|
||||
|
@ -360,7 +360,7 @@
|
|||
<div layout="row" layout-align="space-around center">
|
||||
<div><var:string label:value="Default tasks classification :"/></div>
|
||||
<div>
|
||||
<md-select ng-model="preferences.defaults.SOGoCalendarTasksDefaultClassification">
|
||||
<md-select ng-model="app.preferences.defaults.SOGoCalendarTasksDefaultClassification">
|
||||
<var:foreach list="calendarClassificationsList" item="item">
|
||||
<md-option var:value="item">
|
||||
<var:string value="itemClassificationText"/>
|
||||
|
@ -378,7 +378,7 @@
|
|||
<div layout="row" layout-align="space-around center">
|
||||
<div><var:string label:value="Default reminder :"/></div>
|
||||
<div>
|
||||
<md-select ng-model="preferences.defaults.SOGoCalendarDefaultReminder">
|
||||
<md-select ng-model="app.preferences.defaults.SOGoCalendarDefaultReminder">
|
||||
<var:foreach list="reminderValues" item="item">
|
||||
<md-option var:value="item">
|
||||
<var:string value="itemReminderText"/>
|
||||
|
@ -410,7 +410,7 @@
|
|||
track by $index">
|
||||
<i class="md-avatar" ng-style="{'background-color': '{{preferences.defaults.SOGoCalendarCategoriesColors[item]}}'}"><!-- category color --></i>
|
||||
<md-input-container>
|
||||
<input type="text" ng-model="preferences.defaults.SOGoCalendarCategories[$index]"/>
|
||||
<input type="text" ng-model="app.preferences.defaults.SOGoCalendarCategories[$index]"/>
|
||||
</md-input-container>
|
||||
<md-button
|
||||
ng-click="removeCalendarCategory($index)"
|
||||
|
@ -435,7 +435,7 @@
|
|||
<!-- <div id="calendarAppointmentsInvitationsView"
|
||||
class="tab"> -->
|
||||
<md-checkbox
|
||||
ng-model="preferences.settings.Calendar.PreventInvitations"
|
||||
ng-model="app.preferences.settings.Calendar.PreventInvitations"
|
||||
ng-true-value="1"
|
||||
ng-false-value="0">
|
||||
<var:string label:value="Prevent from being invited to appointments"/>
|
||||
|
@ -446,7 +446,7 @@
|
|||
<var:string label:value="White list for appointment invitations:"/>
|
||||
</label>
|
||||
<md-contact-chips
|
||||
ng-model="preferences.settings.Calendar.PreventInvitationsWhitelist"
|
||||
ng-model="app.preferences.settings.Calendar.PreventInvitationsWhitelist"
|
||||
md-contacts="userFilter($query)"
|
||||
md-contact-name="shortFormat"
|
||||
md-contact-image="image"
|
||||
|
@ -487,7 +487,7 @@
|
|||
preferences.defaults.SOGoContactsCategories
|
||||
track by $index">
|
||||
<md-input-container>
|
||||
<input type="text" ng-model="preferences.defaults.SOGoContactsCategories[$index]"/>
|
||||
<input type="text" ng-model="app.preferences.defaults.SOGoContactsCategories[$index]"/>
|
||||
</md-input-container>
|
||||
<md-button
|
||||
ng-click="removeContactCategory($index)"
|
||||
|
@ -524,7 +524,7 @@
|
|||
<div role="tabpanel" aria-labelledby="mailGeneralView" id="mailGeneralView-content">
|
||||
|
||||
<md-checkbox
|
||||
ng-model="preferences.defaults.SOGoMailShowSubscribedFoldersOnly"
|
||||
ng-model="app.preferences.defaults.SOGoMailShowSubscribedFoldersOnly"
|
||||
ng-true-value="1"
|
||||
ng-false-value="0"
|
||||
label:aria-label="Show subscribed mailboxes only">
|
||||
|
@ -532,7 +532,7 @@
|
|||
</md-checkbox>
|
||||
|
||||
<md-checkbox
|
||||
ng-model="preferences.defaults.SOGoMailSortByThreads"
|
||||
ng-model="app.preferences.defaults.SOGoMailSortByThreads"
|
||||
ng-true-value="1"
|
||||
ng-false-value="0"
|
||||
label:aria-label="Sort messages by threads">
|
||||
|
@ -541,7 +541,7 @@
|
|||
|
||||
<div layout="row" layout-align="space-around center">
|
||||
<md-checkbox
|
||||
ng-model="preferences.defaults.SOGoMailAddOutgoingAddresses"
|
||||
ng-model="app.preferences.defaults.SOGoMailAddOutgoingAddresses"
|
||||
ng-true-value="1"
|
||||
ng-false-value="0"
|
||||
label:arial-label="When sending mail, add unknown recipients to my">
|
||||
|
@ -562,7 +562,7 @@
|
|||
<div layout="row" layout-align="space-around center">
|
||||
<div><var:string label:value="Forward messages:"/></div>
|
||||
<div>
|
||||
<md-select ng-model="preferences.defaults.SOGoMailMessageForwarding">
|
||||
<md-select ng-model="app.preferences.defaults.SOGoMailMessageForwarding">
|
||||
<var:foreach list="messageForwardingList" item="item">
|
||||
<md-option var:value="item">
|
||||
<var:string value="itemMessageForwardingText"/>
|
||||
|
@ -575,7 +575,7 @@
|
|||
<div layout="row" layout-align="space-around center">
|
||||
<div><var:string label:value="When replying to a message:"/></div>
|
||||
<div>
|
||||
<md-select ng-model="preferences.defaults.SOGoMailReplyPlacement">
|
||||
<md-select ng-model="app.preferences.defaults.SOGoMailReplyPlacement">
|
||||
<var:foreach list="replyPlacementList" item="item">
|
||||
<md-option var:value="item">
|
||||
<var:string value="itemReplyPlacementText"/>
|
||||
|
@ -588,7 +588,7 @@
|
|||
<div layout="row" layout-align="space-around center">
|
||||
<div><var:string label:value="And place my signature"/></div>
|
||||
<div>
|
||||
<md-select ng-model="preferences.defaults.SOGoMailSignaturePlacement">
|
||||
<md-select ng-model="app.preferences.defaults.SOGoMailSignaturePlacement">
|
||||
<var:foreach list="signaturePlacementList" item="item">
|
||||
<md-option var:value="item">
|
||||
<var:string value="itemSignaturePlacementText"/>
|
||||
|
@ -601,7 +601,7 @@
|
|||
<div layout="row" layout-align="space-around center">
|
||||
<div><var:string label:value="Compose messages in"/></div>
|
||||
<div>
|
||||
<md-select ng-model="preferences.defaults.SOGoMailComposeMessageType">
|
||||
<md-select ng-model="app.preferences.defaults.SOGoMailComposeMessageType">
|
||||
<var:foreach list="composeMessagesType" item="item">
|
||||
<md-option var:value="item">
|
||||
<var:string value="itemComposeMessagesText"/>
|
||||
|
@ -614,7 +614,7 @@
|
|||
<div layout="row" layout-align="space-around center">
|
||||
<div><var:string label:value="Display remote inline images"/></div>
|
||||
<div>
|
||||
<md-select ng-model="preferences.defaults.SOGoMailDisplayRemoteInlineImages">
|
||||
<md-select ng-model="app.preferences.defaults.SOGoMailDisplayRemoteInlineImages">
|
||||
<var:foreach list="displayRemoteInlineImages" item="item">
|
||||
<md-option var:value="item">
|
||||
<var:string value="itemDisplayRemoteInlineImagesText"/>
|
||||
|
@ -650,13 +650,13 @@
|
|||
preferences.defaults.SOGoSieveFilters
|
||||
track by $index">
|
||||
<md-checkbox
|
||||
ng-model="preferences.defaults.SOGoSieveFilters[$index].active"
|
||||
ng-model="app.preferences.defaults.SOGoSieveFilters[$index].active"
|
||||
ng-true-value="1"
|
||||
ng-false-value="0">
|
||||
<!-- active or not-->
|
||||
</md-checkbox>
|
||||
<md-input-container>
|
||||
<input type="text" ng-model="preferences.defaults.SOGoSieveFilters[$index].name"/>
|
||||
<input type="text" ng-model="app.preferences.defaults.SOGoSieveFilters[$index].name"/>
|
||||
</md-input-container>
|
||||
<md-button ng-click="editMailFilter($index)"
|
||||
type="button"
|
||||
|
@ -729,7 +729,7 @@
|
|||
track by $index">
|
||||
<md-input-container>
|
||||
<input type="text"
|
||||
ng-model="preferences.defaults.AuxiliaryMailAccounts[$index].name"
|
||||
ng-model="app.preferences.defaults.AuxiliaryMailAccounts[$index].name"
|
||||
ng-readonly="$index == 0"/>
|
||||
</md-input-container>
|
||||
<md-button ng-click="editMailAccount($index)"
|
||||
|
@ -770,7 +770,7 @@
|
|||
<div role="tabpanel" aria-labelledby="mailVacationView" id="mailVacationView-content">
|
||||
|
||||
<md-checkbox
|
||||
ng-model="preferences.defaults.Vacation.enabled"
|
||||
ng-model="app.preferences.defaults.Vacation.enabled"
|
||||
ng-true-value="1"
|
||||
ng-false-value="0"
|
||||
label:aria-label="Enable vacation auto reply">
|
||||
|
@ -853,7 +853,7 @@
|
|||
<div role="tabpanel" aria-labelledby="mailForwardView" id="mailForwardView-content">
|
||||
<div id="forwardView" class="tab">
|
||||
<md-checkbox
|
||||
ng-model="preferences.defaults.Forward.enabled"
|
||||
ng-model="app.preferences.defaults.Forward.enabled"
|
||||
ng-true-value="1"
|
||||
ng-false-value="0">
|
||||
<var:string label:value="Forward incoming messages"/>
|
||||
|
@ -863,7 +863,7 @@
|
|||
<label><var:string label:value="Email addresses (separated by commas) :"/><br/>
|
||||
<textarea const:name="forwardAddress"
|
||||
const:id="forwardAddress"
|
||||
ng-model="preferences.defaults.Forward.forwardAddress" />
|
||||
ng-model="app.preferences.defaults.Forward.forwardAddress" />
|
||||
</label><br/>
|
||||
|
||||
<md-checkbox
|
||||
|
|
|
@ -7,10 +7,10 @@
|
|||
xmlns:rsrc="OGo:url"
|
||||
xmlns:label="OGo:label"
|
||||
className="UIxPageFrame"
|
||||
const:userDefaultsKeys="SOGoRefreshViewCheck, SOGoCalendarCategoriesColors,SOGoDefaultCalendar"
|
||||
const:userSettingsKeys="Calendar,ShowCompletedTasks"
|
||||
const:jsFiles="Common/resource.js, Common/user-model.js, Common/acl-model.js, Contacts/card-model.js, Contacts/addressbook-model.js, Appointments/component-model.js, Appointments/calendar-model.js"
|
||||
title="title">
|
||||
title="title"
|
||||
const:userDefaultsKeys="SOGoRefreshViewCheck, SOGoCalendarCategoriesColors, SOGoDefaultCalendar"
|
||||
const:userSettingsKeys="Calendar, ShowCompletedTasks"
|
||||
const:jsFiles="Scheduler.app.js, Scheduler.js, Common.js, Contacts.js">
|
||||
<script type="text/javascript">
|
||||
var firstDayOfWeek = <var:string value="firstDayOfWeek"/>;
|
||||
var dayStartHour = <var:string value="dayStartHour"/>;
|
||||
|
|
|
@ -11,9 +11,7 @@
|
|||
const:toolbar="none"
|
||||
const:popup="YES">
|
||||
|
||||
<div class="calendarUserRights" layout="column">
|
||||
|
||||
|
||||
<div class="calendarUserRights" layout="column">
|
||||
<!-- <var:foreach list="rightTypes" item="currentRightType">
|
||||
<div><span><var:string value="currentRightTypeLabel"/></span>
|
||||
<var:popup list="objectRights" item="currentRight"
|
||||
|
@ -24,9 +22,9 @@
|
|||
/></div>
|
||||
</var:foreach>
|
||||
-->
|
||||
<div layout="row" layout-align="space-around center">
|
||||
<div layout="row" layout-align="space-between center">
|
||||
<var:string label:value="Public"/>
|
||||
<md-select ng-model="selectedUser.rights.Public">
|
||||
<md-select flex="50" ng-model="selectedUser.rights.Public">
|
||||
<var:foreach list="objectRights" item="currentRight">
|
||||
<md-option var:value="currentRight">
|
||||
<var:string value="currentRightLabel"/>
|
||||
|
@ -35,9 +33,9 @@
|
|||
</md-select>
|
||||
</div>
|
||||
|
||||
<div layout="row" layout-align="space-around center">
|
||||
<div layout="row" layout-align="space-between center">
|
||||
<var:string label:value="Confidential"/>
|
||||
<md-select ng-model="selectedUser.rights.Confidential">
|
||||
<md-select flex="50" ng-model="selectedUser.rights.Confidential">
|
||||
<var:foreach list="objectRights" item="currentRight">
|
||||
<md-option var:value="currentRight">
|
||||
<var:string value="currentRightLabel"/>
|
||||
|
@ -46,9 +44,9 @@
|
|||
</md-select>
|
||||
</div>
|
||||
|
||||
<div layout="row" layout-align="space-around center">
|
||||
<div layout="row" layout-align="space-between center">
|
||||
<var:string label:value="Private"/>
|
||||
<md-select ng-model="selectedUser.rights.Private">
|
||||
<md-select flex="50" ng-model="selectedUser.rights.Private">
|
||||
<var:foreach list="objectRights" item="currentRight">
|
||||
<md-option var:value="currentRight">
|
||||
<var:string value="currentRightLabel"/>
|
||||
|
|
|
@ -6,15 +6,16 @@
|
|||
xmlns:const="http://www.skyrix.com/od/constant"
|
||||
xmlns:label="OGo:label"
|
||||
xmlns:uix="OGo:uix">
|
||||
<md-dialog>
|
||||
<md-dialog flex="50" flex-sm="100">
|
||||
<md-dialog-content>
|
||||
<md-subheader><var:string label:value="Access Rights"/> - {{stateAddressbook.name}}</md-subheader>
|
||||
|
||||
<h2 class="md-headline"><var:string label:value="Access Rights"/> - {{folder.name}}</h2>
|
||||
<md-list>
|
||||
<md-list-item ng-repeat="user in users | orderBy:['userClass', 'displayName']">
|
||||
<div layout="column">
|
||||
<md-list-item
|
||||
ng-repeat="user in users | orderBy:['userClass', 'displayName']"
|
||||
ng-click="selectUser(user)">
|
||||
<div layout="column" layout-fill="true">
|
||||
<div layout="row">
|
||||
<md-button ng-click="selectUser(user)">
|
||||
<md-button>
|
||||
<div layout="row" layout-align="space-between center"
|
||||
layout-fill="true">
|
||||
<span class="card-picture" ng-switch="user.userClass">
|
||||
|
@ -28,11 +29,11 @@
|
|||
ng-click="removeUser(user)"
|
||||
type="button"
|
||||
layout="row" layout-align="end center"
|
||||
ng-hide="user.$isSpecial()">
|
||||
ng-hide="user.uid != selectedUser.uid || user.$isSpecial()">
|
||||
<div class="md-icon-delete"><!-- delete --></div>
|
||||
</md-button>
|
||||
</div>
|
||||
<span id="AccessRightList" ng-show="user==selectedUser">
|
||||
<span id="AccessRightList" ng-show="user.uid == selectedUser.uid">
|
||||
<md-checkbox ng-model="user.isSubscribed"
|
||||
arial-label="Subscribe User"
|
||||
ng-disabled="user.wasSubscribed"
|
||||
|
@ -52,25 +53,26 @@
|
|||
</div>
|
||||
<md-divider><!-- divider --></md-divider>
|
||||
</md-list-item>
|
||||
|
||||
<md-autocomplete
|
||||
md-selected-item="userToAdd"
|
||||
md-search-text="searchText"
|
||||
md-selected-item-change="addUser(user)"
|
||||
md-items="user in userFilter(searchText)"
|
||||
md-item-text="user.shortFormat"
|
||||
md-min-length="0"
|
||||
placeholder="Add">
|
||||
<span md-highlight-text="searchText" md-highlight-flags="^i">{{user.shortFormat}}</span>
|
||||
</md-autocomplete>
|
||||
|
||||
<md-list-item>
|
||||
<md-autocomplete
|
||||
class="md-flex"
|
||||
md-selected-item="userToAdd"
|
||||
md-search-text="searchText"
|
||||
md-selected-item-change="addUser(user)"
|
||||
md-items="user in userFilter(searchText)"
|
||||
md-item-text="user.shortFormat"
|
||||
md-min-length="0"
|
||||
placeholder="Add">
|
||||
<span md-highlight-text="searchText" md-highlight-flags="^i">{{user.shortFormat}}</span>
|
||||
</md-autocomplete>
|
||||
</md-list-item>
|
||||
</md-list>
|
||||
|
||||
<div id="aclButtons">
|
||||
<md-button ng-click="closeModal()"><var:string label:value="Close"/></md-button>
|
||||
<md-button ng-click="saveModal()"><var:string label:value="Save"/></md-button>
|
||||
</div>
|
||||
</md-dialog-content>
|
||||
|
||||
<div class="md-actions">
|
||||
<md-button ng-click="closeModal()"><var:string label:value="Close"/></md-button>
|
||||
<md-button class="md-primitive" ng-click="saveModal()"><var:string label:value="Save"/></md-button>
|
||||
</div>
|
||||
</md-dialog>
|
||||
|
||||
</container>
|
||||
|
|
|
@ -226,8 +226,6 @@
|
|||
<script type="text/javascript" rsrc:src="js/vendor/angular-recursion.js"><!-- space --></script>
|
||||
<script type="text/javascript" rsrc:src="js/vendor/angular-vs-repeat.js"><!-- space --></script>
|
||||
<script type="text/javascript" rsrc:src="js/Common/utils.js"><!-- space --></script>
|
||||
<script type="text/javascript" rsrc:src="js/Common/ui.js"><!-- space --></script>
|
||||
<script type="text/javascript" rsrc:src="js/Common/ui-desktop.js"><!-- space --></script>
|
||||
|
||||
<var:if condition="hasProductSpecificJavaScript">
|
||||
<script type="text/javascript"
|
||||
|
|
|
@ -1,10 +1,16 @@
|
|||
module.exports = function(grunt) {
|
||||
var js_files = {
|
||||
'js/Common.js': ['js/Common/Common.app.js', 'js/Common/*.filter.js', 'js/Common/*Controller.js', 'js/Common/*.service.js', 'js/Common/*.directive.js'],
|
||||
'js/Scheduler.js': ['js/Scheduler/*.js'],
|
||||
'js/Contacts.js': ['js/Contacts/*.js'],
|
||||
'js/Mailer.js': ['js/Mailer/*.js'],
|
||||
'js/Preferences.js': ['js/Preferences/*service.js', 'js/Preferences/*Controller.js']
|
||||
};
|
||||
grunt.initConfig({
|
||||
pkg: grunt.file.readJSON('package.json'),
|
||||
sass: {
|
||||
options: {
|
||||
sourceMap: true,
|
||||
// require: 'SassyJSON',
|
||||
noCache: true,
|
||||
includePaths: ['scss/',
|
||||
'bower_components/breakpoint-sass/stylesheets/'
|
||||
|
@ -42,6 +48,20 @@ module.exports = function(grunt) {
|
|||
src: 'css/styles.css'
|
||||
}
|
||||
},
|
||||
concat_sourcemap: {
|
||||
dist: {
|
||||
options: {
|
||||
sourcesContent: false
|
||||
},
|
||||
files: js_files
|
||||
},
|
||||
dev: {
|
||||
options: {
|
||||
sourcesContent: true
|
||||
},
|
||||
files: js_files
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
grunt: {
|
||||
files: ['Gruntfile.js']
|
||||
|
@ -49,12 +69,17 @@ module.exports = function(grunt) {
|
|||
sass: {
|
||||
files: 'scss/**/*.scss',
|
||||
tasks: ['sass']
|
||||
},
|
||||
js: {
|
||||
files: Object.keys(js_files).map(function(key) { return js_files[key]; }),
|
||||
tasks: ['js']
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
grunt.loadNpmTasks('grunt-sass');
|
||||
grunt.loadNpmTasks('grunt-postcss');
|
||||
grunt.loadNpmTasks('grunt-concat-sourcemap');
|
||||
grunt.loadNpmTasks('grunt-contrib-watch');
|
||||
|
||||
grunt.task.registerTask('static', function() {
|
||||
|
@ -119,7 +144,10 @@ module.exports = function(grunt) {
|
|||
}
|
||||
*/
|
||||
});
|
||||
grunt.task.registerTask('build', ['static', 'sass', 'postcss:dist']);
|
||||
grunt.task.registerTask('build', ['static', 'concat_sourcemap:dist', 'sass', 'postcss:dist']);
|
||||
// Tasks for developers
|
||||
grunt.task.registerTask('default', ['watch']);
|
||||
grunt.task.registerTask('css', ['sass', 'postcss:dev']);
|
||||
grunt.task.registerTask('default', ['build', 'watch']);
|
||||
grunt.task.registerTask('js', ['concat_sourcemap:dev']);
|
||||
grunt.task.registerTask('dev', ['css', 'js']);
|
||||
};
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
* @desc The factory we'll use to register with Angular.
|
||||
* @return the Acl constructor
|
||||
*/
|
||||
Acl.factory = ['$q', '$timeout', 'sgSettings', 'sgResource', 'sgUser', function($q, $timeout, Settings, Resource, User) {
|
||||
Acl.factory = ['$q', '$timeout', 'sgSettings', 'Resource', 'User', function($q, $timeout, Settings, Resource, User) {
|
||||
angular.extend(Acl, {
|
||||
$q: $q,
|
||||
$timeout: $timeout,
|
||||
|
@ -30,7 +30,7 @@
|
|||
* @module SOGo.Common
|
||||
* @desc Factory registration of User in Angular module.
|
||||
*/
|
||||
angular.module('SOGo.Common').factory('sgAcl', Acl.factory);
|
||||
angular.module('SOGo.Common').factory('Acl', Acl.factory);
|
||||
|
||||
/**
|
||||
* @function $users
|
|
@ -81,12 +81,12 @@
|
|||
newAddress = baseAddress;
|
||||
}
|
||||
|
||||
if (/theme=mobile/.test(window.location.search)) {
|
||||
newAddress = baseAddress + '/Contacts' + '?theme=mobile';
|
||||
}
|
||||
else {
|
||||
newAddress = baseAddress + '/Contacts';
|
||||
}
|
||||
// if (/theme=mobile/.test(window.location.search)) {
|
||||
// newAddress = baseAddress + '/Contacts' + '?theme=mobile';
|
||||
// }
|
||||
// else {
|
||||
// newAddress = baseAddress + '/Contacts';
|
||||
// }
|
||||
|
||||
return newAddress;
|
||||
};
|
|
@ -0,0 +1,104 @@
|
|||
/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
angular.module('SOGo.Common', ['ngMaterial', 'RecursionHelper'])
|
||||
// md break-points values are hard-coded in angular-material/src/core/util/constant.js
|
||||
// $mdMedia has a built-in support for those values but can also evaluate others
|
||||
// For some reasons, angular-material's break-points don't match the specs
|
||||
// Here we define values according to specs
|
||||
.constant('sgConstant', {
|
||||
'sm': '(max-width: 600px)',
|
||||
'gt-sm': '(min-width: 600px)',
|
||||
'md': '(min-width: 600px) and (max-width: 1024px)',
|
||||
'gt-md': '(min-width: 1025px)',
|
||||
'lg': '(min-width: 1024px) and (max-width: 1280px)',
|
||||
'gt-lg': '(min-width: 1280px)'
|
||||
})
|
||||
|
||||
.config(configure);
|
||||
|
||||
configure.$inject = ['$mdThemingProvider'];
|
||||
function configure($mdThemingProvider) {
|
||||
$mdThemingProvider.definePalette('sogo-green', {
|
||||
'50': 'eaf5e9',
|
||||
'100': 'cbe5c8',
|
||||
'200': 'aad6a5',
|
||||
'300': '88c781',
|
||||
'400': '66b86a',
|
||||
'500': '56b04c',
|
||||
'600': '4da143',
|
||||
'700': '388e3c',
|
||||
'800': '367d2e',
|
||||
'900': '225e1b',
|
||||
'A100': 'b9f6ca',
|
||||
'A200': '69f0ae',
|
||||
'A400': '00e676',
|
||||
'A700': '00c853',
|
||||
'contrastDefaultColor': 'dark',
|
||||
'contrastDarkColors': '50 100 200',
|
||||
'contrastLightColors': '300 400 500 600 700 800 900'
|
||||
});
|
||||
$mdThemingProvider.definePalette('sogo-blue', {
|
||||
'50': 'f0faf9',
|
||||
'100': 'e1f5f3',
|
||||
'200': 'ceebe8',
|
||||
'300': 'bfe0dd',
|
||||
'400': 'b2d6d3',
|
||||
'500': 'a1ccc8',
|
||||
'600': '8ebfbb',
|
||||
'700': '7db3b0',
|
||||
'800': '639997',
|
||||
'900': '4d8080',
|
||||
'A100': 'd4f7fa',
|
||||
'A200': 'c3f5fa',
|
||||
'A400': '53e3f0',
|
||||
'A700': '00b0c0',
|
||||
'contrastDefaultColor': 'light',
|
||||
'contrastDarkColors': ['50', '100', '200'],
|
||||
'contrastLightColors': ['300', '400', '500', '600', '700', '800', '900', 'A100', 'A200', 'A400', 'A700']
|
||||
});
|
||||
$mdThemingProvider.definePalette('sogo-paper', {
|
||||
'50': 'fcf7f8',
|
||||
'100': 'f7f1dc',
|
||||
'200': 'ede5ca',
|
||||
'300': 'e6d8ba',
|
||||
'400': 'e2d2a3',
|
||||
'500': 'd6c48d',
|
||||
'600': 'baa870',
|
||||
'700': '857545',
|
||||
'800': '524517',
|
||||
'900': '433809',
|
||||
'1000': '000000',
|
||||
'A100': 'ffffff',
|
||||
'A200': 'eeeeee',
|
||||
'A400': 'bdbdbd',
|
||||
'A700': '616161',
|
||||
'contrastDefaultColor': 'dark',
|
||||
'contrastLightColors': '800 900'
|
||||
});
|
||||
// Default theme definition
|
||||
// .primaryColor will soon be deprecated in favor of primaryPalette (already on dev builds https://groups.google.com/forum/m/#!topic/ngmaterial/-sXR8CYBMPg)
|
||||
$mdThemingProvider.theme('default')
|
||||
.primaryPalette('sogo-blue', {
|
||||
'default': '300',
|
||||
'hue-1': '100',
|
||||
'hue-2': '400',
|
||||
'hue-3': 'A700'
|
||||
})
|
||||
.accentPalette('sogo-green', {
|
||||
'default': '500',
|
||||
'hue-1': '200',
|
||||
'hue-2': '300',
|
||||
'hue-3': 'A700'
|
||||
})
|
||||
.backgroundPalette('sogo-paper', {
|
||||
'default': '100',
|
||||
'hue-1': '200',
|
||||
'hue-2': '50',
|
||||
'hue-3': '500'
|
||||
});
|
||||
}
|
||||
|
||||
})();
|
|
@ -0,0 +1,125 @@
|
|||
/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* @name Dialog
|
||||
* @constructor
|
||||
*/
|
||||
function Dialog() {
|
||||
}
|
||||
|
||||
/**
|
||||
* @name alert
|
||||
* @desc Show an alert dialog box with a single "OK" button
|
||||
* @param {string} title
|
||||
* @param {string} content
|
||||
*/
|
||||
Dialog.alert = function(title, content) {
|
||||
var alert = this.$modal.alert()
|
||||
.title(title)
|
||||
.content(content)
|
||||
.ok(l('OK'));
|
||||
this.$modal.show(alert);
|
||||
};
|
||||
|
||||
/**
|
||||
* @name confirm
|
||||
* @desc Show a confirmation dialog box with buttons 'Cancel' and 'OK'
|
||||
* @param {string} title
|
||||
* @param {string} content
|
||||
* @returns a promise that resolves if the user has clicked on the 'OK' button
|
||||
*/
|
||||
Dialog.confirm = function(title, content) {
|
||||
var d = this.$q.defer(),
|
||||
confirm = this.$modal.confirm()
|
||||
.title(title)
|
||||
.content(content)
|
||||
.ok(l('OK'))
|
||||
.cancel(l('Cancel'));
|
||||
this.$modal.show(confirm).then(function() {
|
||||
d.resolve();
|
||||
}, function() {
|
||||
d.reject();
|
||||
});
|
||||
return d.promise;
|
||||
};
|
||||
|
||||
/**
|
||||
* @name prompt
|
||||
* @desc Show a primpt dialog box with a input text field and the 'Cancel' and 'OK' buttons
|
||||
* @param {string} title
|
||||
* @param {string} label
|
||||
* @param {object} [options] - use a different input type by setting 'inputType'
|
||||
* @returns a promise that resolves with the input field value
|
||||
*/
|
||||
Dialog.prompt = function(title, label, options) {
|
||||
var o = options || {},
|
||||
d = this.$q.defer();
|
||||
|
||||
this.$modal.show({
|
||||
parent: angular.element(document.body),
|
||||
clickOutsideToClose: true,
|
||||
escapeToClose: true,
|
||||
template: [
|
||||
'<md-dialog flex="50" flex-sm="100">',
|
||||
' <md-dialog-content layout="column">',
|
||||
' <h2 class="md-title" ng-bind="title"></h2>',
|
||||
' <md-input-container>',
|
||||
' <label>' + label + '</label>',
|
||||
' <input type="' + (o.inputType || 'text') + '"',
|
||||
' aria-label="' + title + '"',
|
||||
' ng-model="name" required="required"/>',
|
||||
' </md-input-container>',
|
||||
' </md-dialog-content>',
|
||||
' <div class="md-actions">',
|
||||
' <md-button ng-click="cancel()">',
|
||||
' ' + l('Cancel'),
|
||||
' </md-button>',
|
||||
' <md-button class="md-primary" ng-click="ok()" ng-disabled="!name.length">',
|
||||
' ' + l('OK'),
|
||||
' </md-button>',
|
||||
' </div>',
|
||||
'</md-dialog>'
|
||||
].join(''),
|
||||
controller: PromptDialogController
|
||||
});
|
||||
|
||||
/**
|
||||
* @ngInject
|
||||
*/
|
||||
function PromptDialogController(scope, $mdDialog) {
|
||||
scope.title = title;
|
||||
scope.name = "";
|
||||
scope.cancel = function() {
|
||||
d.reject();
|
||||
$mdDialog.hide();
|
||||
}
|
||||
scope.ok = function() {
|
||||
d.resolve(scope.name);
|
||||
$mdDialog.hide();
|
||||
}
|
||||
}
|
||||
|
||||
return d.promise;
|
||||
};
|
||||
|
||||
/**
|
||||
* @memberof Dialog
|
||||
* @desc The factory we'll register as Dialog in the Angular module SOGo.Common
|
||||
* @ngInject
|
||||
*/
|
||||
DialogService.$inject = ['$q', '$mdDialog'];
|
||||
function DialogService($q, $mdDialog) {
|
||||
angular.extend(Dialog, { $q: $q , $modal: $mdDialog });
|
||||
|
||||
return Dialog; // return constructor
|
||||
};
|
||||
|
||||
/* Factory registration in Angular module */
|
||||
angular
|
||||
.module('SOGo.Common')
|
||||
.factory('Dialog', DialogService);
|
||||
|
||||
})();
|
|
@ -38,7 +38,7 @@
|
|||
* @module SOGo.Common
|
||||
* @desc Factory registration of Resource in Angular module.
|
||||
*/
|
||||
angular.module('SOGo.Common').factory('sgResource', Resource.$factory);
|
||||
angular.module('SOGo.Common').factory('Resource', Resource.$factory);
|
||||
|
||||
/**
|
||||
* @function userResource
|
|
@ -23,7 +23,7 @@
|
|||
* @desc The factory we'll use to register with Angular.
|
||||
* @return the User constructor
|
||||
*/
|
||||
User.factory = ['$q', 'sgSettings', 'sgResource', function($q, Settings, Resource) {
|
||||
User.factory = ['$q', 'sgSettings', 'Resource', function($q, Settings, Resource) {
|
||||
angular.extend(User, {
|
||||
$q: $q,
|
||||
$$resource: new Resource(Settings.activeUser.folderURL, Settings.activeUser)
|
||||
|
@ -36,7 +36,7 @@
|
|||
* @module SOGo.Common
|
||||
* @desc Factory registration of User in Angular module.
|
||||
*/
|
||||
angular.module('SOGo.Common').factory('sgUser', User.factory);
|
||||
angular.module('SOGo.Common').factory('User', User.factory);
|
||||
|
||||
/**
|
||||
* @memberof User
|
||||
|
@ -46,6 +46,8 @@
|
|||
*/
|
||||
User.$filter = function(search) {
|
||||
var param = {search: search};
|
||||
if (!search)
|
||||
return User.$q.when([]);
|
||||
return User.$$resource.fetch(null, 'usersSearch', param).then(function(response) {
|
||||
var results = [];
|
||||
angular.forEach(response.users, function(data) {
|
||||
|
@ -53,6 +55,7 @@
|
|||
var user = new User(data);
|
||||
results.push(user);
|
||||
});
|
||||
User.$users = results;
|
||||
return results;
|
||||
});
|
||||
};
|
|
@ -0,0 +1,19 @@
|
|||
/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
|
||||
/**
|
||||
* @type {angular.Module}
|
||||
*/
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* @ngInject
|
||||
*/
|
||||
decodeUri.$inject = ['$window'];
|
||||
function decodeUri($window) {
|
||||
return $window.decodeURIComponent;
|
||||
}
|
||||
|
||||
angular.module('SOGo.Common')
|
||||
.filter('decodeUri', decodeUri);
|
||||
})();
|
|
@ -0,0 +1,19 @@
|
|||
/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
|
||||
/**
|
||||
* @type {angular.Module}
|
||||
*/
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* @ngInject
|
||||
*/
|
||||
encodeUri.$inject = ['$window'];
|
||||
function encodeUri($window) {
|
||||
return $window.encodeURIComponent;
|
||||
}
|
||||
|
||||
angular.module('SOGo.Common')
|
||||
.filter('encodeUri', encodeUri);
|
||||
})();
|
|
@ -0,0 +1,18 @@
|
|||
/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
|
||||
/**
|
||||
* @type {angular.Module}
|
||||
*/
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* @ngInject
|
||||
*/
|
||||
function loc() {
|
||||
return l;
|
||||
}
|
||||
|
||||
angular.module('SOGo.Common')
|
||||
.filter('loc', loc);
|
||||
})();
|
|
@ -0,0 +1,57 @@
|
|||
/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
|
||||
/**
|
||||
* @type {angular.Module}
|
||||
*/
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* @ngInject
|
||||
*/
|
||||
navController.$inject = ['$scope', '$timeout', '$interval', '$http', '$mdSidenav', '$mdBottomSheet', '$mdMedia', '$log', 'sgConstant'];
|
||||
function navController($scope, $timeout, $interval, $http, $mdSidenav, $mdBottomSheet, $mdMedia, $log, sgConstant) {
|
||||
|
||||
// Show current day in top bar
|
||||
$scope.currentDay = window.currentDay;
|
||||
$timeout(function() {
|
||||
// Update date when day ends
|
||||
$interval(function() {
|
||||
$http.get('../date').success(function(data) {
|
||||
$scope.currentDay = data;
|
||||
});
|
||||
}, 24 * 3600 * 1000);
|
||||
}, window.secondsBeforeTomorrow * 1000);
|
||||
|
||||
$scope.toggleLeft = function () {
|
||||
$mdSidenav('left').toggle()
|
||||
.then(function () {
|
||||
$log.debug("toggle left is done");
|
||||
});
|
||||
};
|
||||
$scope.toggleRight = function () {
|
||||
$mdSidenav('right').toggle()
|
||||
.then(function () {
|
||||
$log.debug("toggle RIGHT is done");
|
||||
});
|
||||
};
|
||||
$scope.openBottomSheet = function() {
|
||||
$mdBottomSheet.show({
|
||||
parent: angular.element(document.getElementById('left-sidenav')),
|
||||
templateUrl: 'bottomSheetTemplate.html'
|
||||
});
|
||||
};
|
||||
$scope.toggleDetailView = function() {
|
||||
var detail = angular.element(document.getElementById('detailView'));
|
||||
detail.toggleClass('sg-close');
|
||||
};
|
||||
$scope.$watch(function() {
|
||||
return $mdMedia(sgConstant['gt-md']);
|
||||
}, function(newVal) {
|
||||
$scope.isGtMedium = newVal;
|
||||
});
|
||||
}
|
||||
|
||||
angular.module('SOGo.Common')
|
||||
.controller('navController', navController);
|
||||
})();
|
|
@ -0,0 +1,32 @@
|
|||
/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* sgEnter - A directive evaluated when the enter key is pressed
|
||||
* @memberof SOGo.Common
|
||||
* @ngInject
|
||||
* @example:
|
||||
|
||||
<input type="text"
|
||||
sg-enter="save($index)" />
|
||||
*/
|
||||
function sgEnter() {
|
||||
var ENTER_KEY = 13;
|
||||
return function(scope, element, attrs) {
|
||||
element.bind("keydown keypress", function(event) {
|
||||
if (event.which === ENTER_KEY) {
|
||||
scope.$apply(function() {
|
||||
scope.$eval(attrs.sgEnter);
|
||||
});
|
||||
event.preventDefault();
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
angular
|
||||
.module('SOGo.Common')
|
||||
.directive('sgEnter', sgEnter);
|
||||
})();
|
|
@ -0,0 +1,29 @@
|
|||
/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* sgEscape - A directive evaluated when the escape key is pressed
|
||||
* @memberof SOGo.Common
|
||||
* @ngInject
|
||||
* @example:
|
||||
|
||||
<input type="text"
|
||||
sg-escape="revertEditing($index)" />
|
||||
*/
|
||||
function sgEscape() {
|
||||
var ESCAPE_KEY = 27;
|
||||
return function(scope, elem, attrs) {
|
||||
elem.bind('keydown', function(event) {
|
||||
if (event.keyCode === ESCAPE_KEY) {
|
||||
scope.$apply(attrs.sgEscape);
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
angular
|
||||
.module('SOGo.Common')
|
||||
.directive('sgEscape', sgEscape);
|
||||
})();
|
|
@ -0,0 +1,30 @@
|
|||
/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* sgFocusOn - A directive that sets the focus on its element when the specified string is broadcasted
|
||||
* @memberof SOGo.Common
|
||||
* @see {@link SOGo.Common.sgFocus}
|
||||
* @ngInject
|
||||
* @example:
|
||||
|
||||
<input type="text"
|
||||
sg-focus-on="username" />
|
||||
*/
|
||||
function sgFocusOn() {
|
||||
return function(scope, elem, attr) {
|
||||
scope.$on('sgFocusOn', function(e, name) {
|
||||
if (name === attr.sgFocusOn) {
|
||||
elem[0].focus();
|
||||
elem[0].select();
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
angular
|
||||
.module('SOGo.Common')
|
||||
.directive('sgFocusOn', sgFocusOn);
|
||||
})();
|
|
@ -0,0 +1,25 @@
|
|||
/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* sgFocus - A service to set the focus on the element associated to a specific string
|
||||
* @memberof SOGo.Common
|
||||
* @param {string} name - the string identifier of the element
|
||||
* @see {@link SOGo.Common.sgFocusOn}
|
||||
* @ngInject
|
||||
*/
|
||||
sgFocus.$inject = ['$rootScope', '$timeout'];
|
||||
function sgFocus($rootScope, $timeout) {
|
||||
return function(name) {
|
||||
$timeout(function() {
|
||||
$rootScope.$broadcast('sgFocusOn', name);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
angular
|
||||
.module('SOGo.Common')
|
||||
.factory('sgFocus', sgFocus);
|
||||
})();
|
|
@ -0,0 +1,44 @@
|
|||
/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
/*
|
||||
* sgFolderStylesheet - Add CSS stylesheet for folder (addressbook or calendar)
|
||||
* @memberof SOGo.Common
|
||||
* @restrict attribute
|
||||
* @param {object} ngModel - the object literal describing the folder (an Addressbook or Calendar instance)
|
||||
* @example:
|
||||
|
||||
<div sg-folder-stylesheet="true"
|
||||
ng-repeat="calendar in calendars.list"
|
||||
ng-model="calendar" />
|
||||
</div>
|
||||
*/
|
||||
function sgFolderStylesheet() {
|
||||
return {
|
||||
restrict: 'A',
|
||||
require: 'ngModel',
|
||||
scope: {
|
||||
ngModel: '='
|
||||
},
|
||||
template: [
|
||||
'<style type="text/css">',
|
||||
' .bg-folder{{ ngModel.id }} {',
|
||||
' background-color: {{ ngModel.color }} !important;',
|
||||
' }',
|
||||
' .fg-folder{{ ngModel.id }} {',
|
||||
' color: {{ ngModel.color }} !important;',
|
||||
' }',
|
||||
' .checkbox-folder{{ ngModel.id }}.md-checked .md-icon {',
|
||||
' background-color: {{ ngModel.color }} !important;',
|
||||
' }',
|
||||
'</style>'
|
||||
].join('')
|
||||
}
|
||||
}
|
||||
|
||||
angular
|
||||
.module('SOGo.Common')
|
||||
.directive('sgFolderStylesheet', sgFolderStylesheet);
|
||||
})();
|
|
@ -0,0 +1,40 @@
|
|||
/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* sgGravatarImage - A simple Gravatar directive (based on http://blog.lingohub.com/2014/08/better-ux-with-angularjs-directives/)
|
||||
* @memberof SOGo.Common
|
||||
* @example:
|
||||
<sg-gravatar-image email="test@email.com" size="50"></sg-gravatar-image>
|
||||
*/
|
||||
|
||||
function sgGravatarImage() {
|
||||
return {
|
||||
restrict: 'AE',
|
||||
replace: true,
|
||||
required: 'email',
|
||||
template: '<img ng-src="https://www.gravatar.com/avatar/{{hash}}?s={{size}}&d=wavatar" />',
|
||||
link: function(scope, element, attrs) {
|
||||
attrs.$observe('email', function(value) {
|
||||
if (!value) { return; }
|
||||
|
||||
// MD5 (Message-Digest Algorithm) by WebToolkit
|
||||
var md5=function(s){function L(k,d){return(k<<d)|(k>>>(32-d));}function K(G,k){var I,d,F,H,x;F=(G&2147483648);H=(k&2147483648);I=(G&1073741824);d=(k&1073741824);x=(G&1073741823)+(k&1073741823);if(I&d){return(x^2147483648^F^H);}if(I|d){if(x&1073741824){return(x^3221225472^F^H);}else{return(x^1073741824^F^H);}}else{return(x^F^H);}}function r(d,F,k){return(d&F)|((~d)&k);}function q(d,F,k){return(d&k)|(F&(~k));}function p(d,F,k){return(d^F^k);}function n(d,F,k){return(F^(d|(~k)));}function u(G,F,aa,Z,k,H,I){G=K(G,K(K(r(F,aa,Z),k),I));return K(L(G,H),F);}function f(G,F,aa,Z,k,H,I){G=K(G,K(K(q(F,aa,Z),k),I));return K(L(G,H),F);}function D(G,F,aa,Z,k,H,I){G=K(G,K(K(p(F,aa,Z),k),I));return K(L(G,H),F);}function t(G,F,aa,Z,k,H,I){G=K(G,K(K(n(F,aa,Z),k),I));return K(L(G,H),F);}function e(G){var Z;var F=G.length;var x=F+8;var k=(x-(x%64))/64;var I=(k+1)*16;var aa=Array(I-1);var d=0;var H=0;while(H<F){Z=(H-(H%4))/4;d=(H%4)*8;aa[Z]=(aa[Z]|(G.charCodeAt(H)<<d));H++;}Z=(H-(H%4))/4;d=(H%4)*8;aa[Z]=aa[Z]|(128<<d);aa[I-2]=F<<3;aa[I-1]=F>>>29;return aa;}function B(x){var k="",F="",G,d;for(d=0;d<=3;d++){G=(x>>>(d*8))&255;F="0"+G.toString(16);k=k+F.substr(F.length-2,2);}return k;}function J(k){k=k.replace(/rn/g,"n");var d="";for(var F=0;F<k.length;F++){var x=k.charCodeAt(F);if(x<128){d+=String.fromCharCode(x);}else{if((x>127)&&(x<2048)){d+=String.fromCharCode((x>>6)|192);d+=String.fromCharCode((x&63)|128);}else{d+=String.fromCharCode((x>>12)|224);d+=String.fromCharCode(((x>>6)&63)|128);d+=String.fromCharCode((x&63)|128);}}}return d;}var C=Array();var P,h,E,v,g,Y,X,W,V;var S=7,Q=12,N=17,M=22;var A=5,z=9,y=14,w=20;var o=4,m=11,l=16,j=23;var U=6,T=10,R=15,O=21;s=J(s);C=e(s);Y=1732584193;X=4023233417;W=2562383102;V=271733878;for(P=0;P<C.length;P+=16){h=Y;E=X;v=W;g=V;Y=u(Y,X,W,V,C[P+0],S,3614090360);V=u(V,Y,X,W,C[P+1],Q,3905402710);W=u(W,V,Y,X,C[P+2],N,606105819);X=u(X,W,V,Y,C[P+3],M,3250441966);Y=u(Y,X,W,V,C[P+4],S,4118548399);V=u(V,Y,X,W,C[P+5],Q,1200080426);W=u(W,V,Y,X,C[P+6],N,2821735955);X=u(X,W,V,Y,C[P+7],M,4249261313);Y=u(Y,X,W,V,C[P+8],S,1770035416);V=u(V,Y,X,W,C[P+9],Q,2336552879);W=u(W,V,Y,X,C[P+10],N,4294925233);X=u(X,W,V,Y,C[P+11],M,2304563134);Y=u(Y,X,W,V,C[P+12],S,1804603682);V=u(V,Y,X,W,C[P+13],Q,4254626195);W=u(W,V,Y,X,C[P+14],N,2792965006);X=u(X,W,V,Y,C[P+15],M,1236535329);Y=f(Y,X,W,V,C[P+1],A,4129170786);V=f(V,Y,X,W,C[P+6],z,3225465664);W=f(W,V,Y,X,C[P+11],y,643717713);X=f(X,W,V,Y,C[P+0],w,3921069994);Y=f(Y,X,W,V,C[P+5],A,3593408605);V=f(V,Y,X,W,C[P+10],z,38016083);W=f(W,V,Y,X,C[P+15],y,3634488961);X=f(X,W,V,Y,C[P+4],w,3889429448);Y=f(Y,X,W,V,C[P+9],A,568446438);V=f(V,Y,X,W,C[P+14],z,3275163606);W=f(W,V,Y,X,C[P+3],y,4107603335);X=f(X,W,V,Y,C[P+8],w,1163531501);Y=f(Y,X,W,V,C[P+13],A,2850285829);V=f(V,Y,X,W,C[P+2],z,4243563512);W=f(W,V,Y,X,C[P+7],y,1735328473);X=f(X,W,V,Y,C[P+12],w,2368359562);Y=D(Y,X,W,V,C[P+5],o,4294588738);V=D(V,Y,X,W,C[P+8],m,2272392833);W=D(W,V,Y,X,C[P+11],l,1839030562);X=D(X,W,V,Y,C[P+14],j,4259657740);Y=D(Y,X,W,V,C[P+1],o,2763975236);V=D(V,Y,X,W,C[P+4],m,1272893353);W=D(W,V,Y,X,C[P+7],l,4139469664);X=D(X,W,V,Y,C[P+10],j,3200236656);Y=D(Y,X,W,V,C[P+13],o,681279174);V=D(V,Y,X,W,C[P+0],m,3936430074);W=D(W,V,Y,X,C[P+3],l,3572445317);X=D(X,W,V,Y,C[P+6],j,76029189);Y=D(Y,X,W,V,C[P+9],o,3654602809);V=D(V,Y,X,W,C[P+12],m,3873151461);W=D(W,V,Y,X,C[P+15],l,530742520);X=D(X,W,V,Y,C[P+2],j,3299628645);Y=t(Y,X,W,V,C[P+0],U,4096336452);V=t(V,Y,X,W,C[P+7],T,1126891415);W=t(W,V,Y,X,C[P+14],R,2878612391);X=t(X,W,V,Y,C[P+5],O,4237533241);Y=t(Y,X,W,V,C[P+12],U,1700485571);V=t(V,Y,X,W,C[P+3],T,2399980690);W=t(W,V,Y,X,C[P+10],R,4293915773);X=t(X,W,V,Y,C[P+1],O,2240044497);Y=t(Y,X,W,V,C[P+8],U,1873313359);V=t(V,Y,X,W,C[P+15],T,4264355552);W=t(W,V,Y,X,C[P+6],R,2734768916);X=t(X,W,V,Y,C[P+13],O,1309151649);Y=t(Y,X,W,V,C[P+4],U,4149444226);V=t(V,Y,X,W,C[P+11],T,3174756917);W=t(W,V,Y,X,C[P+2],R,718787259);X=t(X,W,V,Y,C[P+9],O,3951481745);Y=K(Y,h);X=K(X,E);W=K(W,v);V=K(V,g);}var i=B(Y)+B(X)+B(W)+B(V);return i.toLowerCase();};
|
||||
|
||||
scope.hash = md5(value.toLowerCase());
|
||||
scope.size = attrs.size;
|
||||
|
||||
if (angular.isUndefined(scope.size)) {
|
||||
scope.size = 60; // default to 60 pixels
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
angular
|
||||
.module('SOGo.Common')
|
||||
.directive('sgGravatarImage', sgGravatarImage);
|
||||
})();
|
|
@ -0,0 +1,101 @@
|
|||
/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
/*
|
||||
* sgSearch - Search within a list of items
|
||||
* @memberof SOGo.Common
|
||||
* @restrict attribute
|
||||
* @param {function} sgSearch - the function to call when performing a search.
|
||||
* Two variables are available: searchField and searchText.
|
||||
* @example:
|
||||
|
||||
<div sg-search="mailbox.$filter({ sort: 'date', asc: false }, [{ searchBy: searchField, searchInput: searchText }])">
|
||||
<md-input-container>
|
||||
<input name="search" type="search"/>
|
||||
</md-input-container>
|
||||
<md-select class="sg-toolbar-sort md-contrast-light">
|
||||
<md-option value="subject">Subject</md-option>
|
||||
<md-option value="sender">sender</md-option>
|
||||
</md-select>
|
||||
</div>
|
||||
*/
|
||||
sgSearch.$inject = ['$compile'];
|
||||
function sgSearch($compile) {
|
||||
return {
|
||||
restrict: 'A',
|
||||
controller: 'sgSearchController',
|
||||
controllerAs: '$sgSearchController',
|
||||
// See http://stackoverflow.com/questions/19224028/add-directives-from-directive-in-angularjs
|
||||
// for reasons of using terminal and priority
|
||||
terminal: true,
|
||||
priority: 1000,
|
||||
scope: {
|
||||
doSearch: '&sgSearch'
|
||||
},
|
||||
compile: compile
|
||||
};
|
||||
|
||||
function compile(tElement, tAttr) {
|
||||
var mdInputEl = tElement.find('md-input-container'),
|
||||
inputEl = tElement.find('input'),
|
||||
selectEl = tElement.find('md-select');
|
||||
|
||||
inputEl.attr('ng-model', '$sgSearchController.searchText');
|
||||
inputEl.attr('ng-model-options', '$sgSearchController.searchTextOptions');
|
||||
if (selectEl) {
|
||||
selectEl.attr('ng-model', '$sgSearchController.searchField');
|
||||
selectEl.attr('ng-change', '$sgSearchController.onChange()');
|
||||
}
|
||||
|
||||
return function postLink(scope, iElement, iAttr, controller) {
|
||||
$compile(mdInputEl)(scope);
|
||||
if (selectEl)
|
||||
$compile(selectEl)(scope);
|
||||
$compile(tElement.find('md-button'))(scope.$parent);
|
||||
|
||||
scope.$watch('$sgSearchController.searchText', angular.bind(controller, controller.onChange));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @ngInject
|
||||
*/
|
||||
sgSearchController.$inject = ['$scope', '$element'];
|
||||
function sgSearchController($scope, $element) {
|
||||
// Controller variables
|
||||
this.previous = { searchText: '', searchField: '' };
|
||||
this.searchText = '';
|
||||
this.searchField = $element.find('md-option').attr('value'); // defaults to first option
|
||||
|
||||
// Model options
|
||||
this.searchTextOptions = {
|
||||
updateOn: 'default blur',
|
||||
debounce: {
|
||||
default: 300,
|
||||
blur: 0
|
||||
}
|
||||
};
|
||||
|
||||
// Method to call on data changes
|
||||
this.onChange = function(value) {
|
||||
if (typeof this.searchText != 'undefined') {
|
||||
if (this.searchText != this.previous.searchText || this.searchField != this.previous.searchField) {
|
||||
if (this.searchText.length > 2 || this.searchText.length == 0) {
|
||||
// See https://github.com/angular/angular.js/issues/7635
|
||||
// for why we need to use $scope here
|
||||
$scope.doSearch({ searchText: this.searchText, searchField: this.searchField });
|
||||
}
|
||||
this.previous = { searchText: this.searchText, searchField: this.searchField };
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
angular
|
||||
.module('SOGo.Common')
|
||||
.controller('sgSearchController', sgSearchController)
|
||||
.directive('sgSearch', sgSearch);
|
||||
})();
|
|
@ -0,0 +1,93 @@
|
|||
/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
/*
|
||||
* sgSubscribe - Common subscription widget
|
||||
* @restrict class or attribute
|
||||
* @param {string} sgSubscribe - the folder type
|
||||
* @param {function} sgSubscribeOnSelect - the function to call when subscribing to a folder.
|
||||
* One variable is available: folderData.
|
||||
* @ngInject
|
||||
* @example:
|
||||
|
||||
<md-button sg-subscribe="contact" sg-subscribe-on-select="subscribeToFolder">Subscribe ..</md-button>
|
||||
*/
|
||||
sgSubscribe.$inject = ['User'];
|
||||
function sgSubscribe(User) {
|
||||
return {
|
||||
restrict: 'A',
|
||||
scope: {
|
||||
folderType: '@sgSubscribe',
|
||||
onFolderSelect: '&sgSubscribeOnSelect'
|
||||
},
|
||||
replace: false,
|
||||
bindToController: true,
|
||||
controller: sgSubscribeDialogController,
|
||||
controllerAs: 'vm',
|
||||
link: link
|
||||
}
|
||||
sgSubscribeDialogController.$inject = ['$mdDialog'];
|
||||
function sgSubscribeDialogController($mdDialog) {
|
||||
var vm = this;
|
||||
vm.showDialog = function() {
|
||||
$mdDialog.show({
|
||||
templateUrl: '../Contacts/UIxContactsUserFolders',
|
||||
clickOutsideToClose: true,
|
||||
//scope: vm,
|
||||
//preserveScope: true,
|
||||
locals: {
|
||||
folderType: vm.folderType,
|
||||
onFolderSelect: vm.onFolderSelect
|
||||
//User: User
|
||||
},
|
||||
controller: sgSubscribeController,
|
||||
controllerAs: 'vm'
|
||||
});
|
||||
/**
|
||||
* @ngInject
|
||||
*/
|
||||
sgSubscribeController.$inject = ['folderType', 'onFolderSelect', 'User'];
|
||||
function sgSubscribeController(folderType, onFolderSelect, User) {
|
||||
var vm = this;
|
||||
vm.selectedUser = null;
|
||||
|
||||
vm.searchTextOptions = {
|
||||
updateOn: 'default blur',
|
||||
debounce: {
|
||||
default: 300,
|
||||
blur: 0
|
||||
}
|
||||
};
|
||||
|
||||
vm.onChange = function() {
|
||||
User.$filter(vm.searchText).then(function(matches) {
|
||||
vm.users = matches;
|
||||
});
|
||||
};
|
||||
|
||||
vm.selectUser = function(i) {
|
||||
// Fetch folders of specific type for selected user
|
||||
vm.users[i].$folders(folderType).then(function() {
|
||||
vm.selectedUser = vm.users[i];
|
||||
});
|
||||
};
|
||||
|
||||
// Callback upon subscription to a folder
|
||||
vm.selectFolder = function(folder) {
|
||||
onFolderSelect({folderData: folder});
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
function link(scope, element, attrs, controller) {
|
||||
var inputEl = element.find('input');
|
||||
element.on('click', controller.showDialog);
|
||||
}
|
||||
}
|
||||
|
||||
angular
|
||||
.module('SOGo.Common')
|
||||
.directive('sgSubscribe', sgSubscribe);
|
||||
})();
|
|
@ -4,234 +4,15 @@
|
|||
(function() {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* @name Dialog
|
||||
* @constructor
|
||||
*/
|
||||
function Dialog() {
|
||||
}
|
||||
|
||||
/**
|
||||
* @name alert
|
||||
* @desc Show an alert dialog box with a single "OK" button
|
||||
* @param {string} title
|
||||
* @param {string} content
|
||||
*/
|
||||
Dialog.alert = function(title, content) {
|
||||
var alert = this.$modal.alert()
|
||||
.title(title)
|
||||
.content(content)
|
||||
.ok(l('OK'));
|
||||
this.$modal.show(alert);
|
||||
};
|
||||
|
||||
/**
|
||||
* @name confirm
|
||||
* @desc Show a confirmation dialog box with buttons 'Cancel' and 'OK'
|
||||
* @param {string} title
|
||||
* @param {string} content
|
||||
* @returns a promise that resolves if the user has clicked on the 'OK' button
|
||||
*/
|
||||
Dialog.confirm = function(title, content) {
|
||||
var d = this.$q.defer(),
|
||||
confirm = this.$modal.confirm()
|
||||
.title(title)
|
||||
.content(content)
|
||||
.ok(l('OK'))
|
||||
.cancel(l('Cancel'));
|
||||
this.$modal.show(confirm).then(function() {
|
||||
d.resolve();
|
||||
}, function() {
|
||||
d.reject();
|
||||
});
|
||||
return d.promise;
|
||||
};
|
||||
|
||||
/**
|
||||
* @name prompt
|
||||
* @desc Show a primpt dialog box with a input text field and the 'Cancel' and 'OK' buttons
|
||||
* @param {string} title
|
||||
* @param {string} label
|
||||
* @param {object} [options] - use a different input type by setting 'inputType'
|
||||
* @returns a promise that resolves with the input field value
|
||||
*/
|
||||
Dialog.prompt = function(title, label, options) {
|
||||
var o = options || {},
|
||||
d = this.$q.defer();
|
||||
|
||||
this.$modal.show({
|
||||
parent: angular.element(document.body),
|
||||
clickOutsideToClose: true,
|
||||
escapeToClose: true,
|
||||
template: [
|
||||
'<md-dialog flex="30" flex-sm="100">',
|
||||
' <md-dialog-content layout="column">',
|
||||
' <h2 class="md-title" ng-bind="title"></h2>',
|
||||
' <md-input-container>',
|
||||
' <label>' + label + '</label>',
|
||||
' <input type="' + (o.inputType || 'text') + '"',
|
||||
' aria-label="' + title + '"',
|
||||
' ng-model="name" required="required"/>',
|
||||
' </md-input-container>',
|
||||
' </md-dialog-content>',
|
||||
' <div class="md-actions">',
|
||||
' <md-button ng-click="cancel()">',
|
||||
' ' + l('Cancel'),
|
||||
' </md-button>',
|
||||
' <md-button class="md-primary" ng-click="ok()" ng-disabled="!name.length">',
|
||||
' ' + l('OK'),
|
||||
' </md-button>',
|
||||
' </div>',
|
||||
'</md-dialog>'
|
||||
].join(''),
|
||||
controller: PromptDialogController
|
||||
});
|
||||
|
||||
function PromptDialogController(scope, $mdDialog) {
|
||||
scope.title = title;
|
||||
scope.name = "";
|
||||
scope.cancel = function() {
|
||||
d.reject();
|
||||
$mdDialog.hide();
|
||||
}
|
||||
scope.ok = function() {
|
||||
d.resolve(scope.name);
|
||||
$mdDialog.hide();
|
||||
}
|
||||
}
|
||||
|
||||
return d.promise;
|
||||
};
|
||||
|
||||
/**
|
||||
* @memberof Dialog
|
||||
* @desc The factory we'll register as sgDialog in the Angular module SOGo.UIDesktop
|
||||
*/
|
||||
Dialog.$factory = ['$q', '$mdDialog', function($q, $mdDialog) {
|
||||
angular.extend(Dialog, { $q: $q , $modal: $mdDialog });
|
||||
|
||||
return Dialog; // return constructor
|
||||
}];
|
||||
|
||||
/* Angular module instanciation */
|
||||
angular.module('SOGo.UIDesktop', ['ngMaterial', 'RecursionHelper'])
|
||||
|
||||
/* Factory registration in Angular module */
|
||||
.factory('sgDialog', Dialog.$factory)
|
||||
|
||||
/**
|
||||
* sgEnter - A directive evaluated when the enter key is pressed
|
||||
* @memberof SOGo.UIDesktop
|
||||
* @example:
|
||||
|
||||
<input type="text"
|
||||
sg-enter="save($index)" />
|
||||
*/
|
||||
.directive('sgEnter', function() {
|
||||
var ENTER_KEY = 13;
|
||||
return function(scope, element, attrs) {
|
||||
element.bind("keydown keypress", function(event) {
|
||||
if (event.which === ENTER_KEY) {
|
||||
scope.$apply(function() {
|
||||
scope.$eval(attrs.sgEnter);
|
||||
});
|
||||
event.preventDefault();
|
||||
}
|
||||
});
|
||||
};
|
||||
})
|
||||
|
||||
/**
|
||||
* sgEscape - A directive evaluated when the escape key is pressed
|
||||
* @memberof SOGo.UIDesktop
|
||||
* @example:
|
||||
|
||||
<input type="text"
|
||||
sg-escape="revertEditing($index)" />
|
||||
*/
|
||||
.directive('sgEscape', function() {
|
||||
var ESCAPE_KEY = 27;
|
||||
return function(scope, elem, attrs) {
|
||||
elem.bind('keydown', function(event) {
|
||||
if (event.keyCode === ESCAPE_KEY) {
|
||||
scope.$apply(attrs.sgEscape);
|
||||
}
|
||||
});
|
||||
};
|
||||
})
|
||||
|
||||
/**
|
||||
* sgFocusOn - A directive that sets the focus on its element when the specified string is broadcasted
|
||||
* @memberof SOGo.UIDesktop
|
||||
* @see {@link SOGo.UIDesktop.sgFocus}
|
||||
* @example:
|
||||
|
||||
<input type="text"
|
||||
sg-focus-on="username" />
|
||||
*/
|
||||
.directive('sgFocusOn', function() {
|
||||
return function(scope, elem, attr) {
|
||||
scope.$on('sgFocusOn', function(e, name) {
|
||||
if (name === attr.sgFocusOn) {
|
||||
elem[0].focus();
|
||||
elem[0].select();
|
||||
}
|
||||
});
|
||||
};
|
||||
})
|
||||
|
||||
/**
|
||||
* sgGravatarImage - A simple Gravatar directive (based on http://blog.lingohub.com/2014/08/better-ux-with-angularjs-directives/)
|
||||
* @memberof SOGo.UIDesktop
|
||||
* @example:
|
||||
|
||||
<sg-gravatar-image email="test@email.com" size="50"></sg-gravatar-image>
|
||||
*/
|
||||
.directive('sgGravatarImage', function () {
|
||||
return {
|
||||
restrict: 'AE',
|
||||
replace: true,
|
||||
required: 'email',
|
||||
template: '<img ng-src="https://www.gravatar.com/avatar/{{hash}}?s={{size}}&d=wavatar" />',
|
||||
link: function (scope, element, attrs) {
|
||||
attrs.$observe('email', function (value) {
|
||||
if(!value) { return; }
|
||||
|
||||
// MD5 (Message-Digest Algorithm) by WebToolkit
|
||||
var md5=function(s){function L(k,d){return(k<<d)|(k>>>(32-d));}function K(G,k){var I,d,F,H,x;F=(G&2147483648);H=(k&2147483648);I=(G&1073741824);d=(k&1073741824);x=(G&1073741823)+(k&1073741823);if(I&d){return(x^2147483648^F^H);}if(I|d){if(x&1073741824){return(x^3221225472^F^H);}else{return(x^1073741824^F^H);}}else{return(x^F^H);}}function r(d,F,k){return(d&F)|((~d)&k);}function q(d,F,k){return(d&k)|(F&(~k));}function p(d,F,k){return(d^F^k);}function n(d,F,k){return(F^(d|(~k)));}function u(G,F,aa,Z,k,H,I){G=K(G,K(K(r(F,aa,Z),k),I));return K(L(G,H),F);}function f(G,F,aa,Z,k,H,I){G=K(G,K(K(q(F,aa,Z),k),I));return K(L(G,H),F);}function D(G,F,aa,Z,k,H,I){G=K(G,K(K(p(F,aa,Z),k),I));return K(L(G,H),F);}function t(G,F,aa,Z,k,H,I){G=K(G,K(K(n(F,aa,Z),k),I));return K(L(G,H),F);}function e(G){var Z;var F=G.length;var x=F+8;var k=(x-(x%64))/64;var I=(k+1)*16;var aa=Array(I-1);var d=0;var H=0;while(H<F){Z=(H-(H%4))/4;d=(H%4)*8;aa[Z]=(aa[Z]|(G.charCodeAt(H)<<d));H++;}Z=(H-(H%4))/4;d=(H%4)*8;aa[Z]=aa[Z]|(128<<d);aa[I-2]=F<<3;aa[I-1]=F>>>29;return aa;}function B(x){var k="",F="",G,d;for(d=0;d<=3;d++){G=(x>>>(d*8))&255;F="0"+G.toString(16);k=k+F.substr(F.length-2,2);}return k;}function J(k){k=k.replace(/rn/g,"n");var d="";for(var F=0;F<k.length;F++){var x=k.charCodeAt(F);if(x<128){d+=String.fromCharCode(x);}else{if((x>127)&&(x<2048)){d+=String.fromCharCode((x>>6)|192);d+=String.fromCharCode((x&63)|128);}else{d+=String.fromCharCode((x>>12)|224);d+=String.fromCharCode(((x>>6)&63)|128);d+=String.fromCharCode((x&63)|128);}}}return d;}var C=Array();var P,h,E,v,g,Y,X,W,V;var S=7,Q=12,N=17,M=22;var A=5,z=9,y=14,w=20;var o=4,m=11,l=16,j=23;var U=6,T=10,R=15,O=21;s=J(s);C=e(s);Y=1732584193;X=4023233417;W=2562383102;V=271733878;for(P=0;P<C.length;P+=16){h=Y;E=X;v=W;g=V;Y=u(Y,X,W,V,C[P+0],S,3614090360);V=u(V,Y,X,W,C[P+1],Q,3905402710);W=u(W,V,Y,X,C[P+2],N,606105819);X=u(X,W,V,Y,C[P+3],M,3250441966);Y=u(Y,X,W,V,C[P+4],S,4118548399);V=u(V,Y,X,W,C[P+5],Q,1200080426);W=u(W,V,Y,X,C[P+6],N,2821735955);X=u(X,W,V,Y,C[P+7],M,4249261313);Y=u(Y,X,W,V,C[P+8],S,1770035416);V=u(V,Y,X,W,C[P+9],Q,2336552879);W=u(W,V,Y,X,C[P+10],N,4294925233);X=u(X,W,V,Y,C[P+11],M,2304563134);Y=u(Y,X,W,V,C[P+12],S,1804603682);V=u(V,Y,X,W,C[P+13],Q,4254626195);W=u(W,V,Y,X,C[P+14],N,2792965006);X=u(X,W,V,Y,C[P+15],M,1236535329);Y=f(Y,X,W,V,C[P+1],A,4129170786);V=f(V,Y,X,W,C[P+6],z,3225465664);W=f(W,V,Y,X,C[P+11],y,643717713);X=f(X,W,V,Y,C[P+0],w,3921069994);Y=f(Y,X,W,V,C[P+5],A,3593408605);V=f(V,Y,X,W,C[P+10],z,38016083);W=f(W,V,Y,X,C[P+15],y,3634488961);X=f(X,W,V,Y,C[P+4],w,3889429448);Y=f(Y,X,W,V,C[P+9],A,568446438);V=f(V,Y,X,W,C[P+14],z,3275163606);W=f(W,V,Y,X,C[P+3],y,4107603335);X=f(X,W,V,Y,C[P+8],w,1163531501);Y=f(Y,X,W,V,C[P+13],A,2850285829);V=f(V,Y,X,W,C[P+2],z,4243563512);W=f(W,V,Y,X,C[P+7],y,1735328473);X=f(X,W,V,Y,C[P+12],w,2368359562);Y=D(Y,X,W,V,C[P+5],o,4294588738);V=D(V,Y,X,W,C[P+8],m,2272392833);W=D(W,V,Y,X,C[P+11],l,1839030562);X=D(X,W,V,Y,C[P+14],j,4259657740);Y=D(Y,X,W,V,C[P+1],o,2763975236);V=D(V,Y,X,W,C[P+4],m,1272893353);W=D(W,V,Y,X,C[P+7],l,4139469664);X=D(X,W,V,Y,C[P+10],j,3200236656);Y=D(Y,X,W,V,C[P+13],o,681279174);V=D(V,Y,X,W,C[P+0],m,3936430074);W=D(W,V,Y,X,C[P+3],l,3572445317);X=D(X,W,V,Y,C[P+6],j,76029189);Y=D(Y,X,W,V,C[P+9],o,3654602809);V=D(V,Y,X,W,C[P+12],m,3873151461);W=D(W,V,Y,X,C[P+15],l,530742520);X=D(X,W,V,Y,C[P+2],j,3299628645);Y=t(Y,X,W,V,C[P+0],U,4096336452);V=t(V,Y,X,W,C[P+7],T,1126891415);W=t(W,V,Y,X,C[P+14],R,2878612391);X=t(X,W,V,Y,C[P+5],O,4237533241);Y=t(Y,X,W,V,C[P+12],U,1700485571);V=t(V,Y,X,W,C[P+3],T,2399980690);W=t(W,V,Y,X,C[P+10],R,4293915773);X=t(X,W,V,Y,C[P+1],O,2240044497);Y=t(Y,X,W,V,C[P+8],U,1873313359);V=t(V,Y,X,W,C[P+15],T,4264355552);W=t(W,V,Y,X,C[P+6],R,2734768916);X=t(X,W,V,Y,C[P+13],O,1309151649);Y=t(Y,X,W,V,C[P+4],U,4149444226);V=t(V,Y,X,W,C[P+11],T,3174756917);W=t(W,V,Y,X,C[P+2],R,718787259);X=t(X,W,V,Y,C[P+9],O,3951481745);Y=K(Y,h);X=K(X,E);W=K(W,v);V=K(V,g);}var i=B(Y)+B(X)+B(W)+B(V);return i.toLowerCase();};
|
||||
|
||||
scope.hash = md5(value.toLowerCase());
|
||||
scope.size = attrs.size;
|
||||
|
||||
if(angular.isUndefined(scope.size)) {
|
||||
scope.size = 60; // default to 60 pixels
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
})
|
||||
|
||||
/**
|
||||
* sgFocus - A service to set the focus on the element associated to a specific string
|
||||
* @memberof SOGo.UIDesktop
|
||||
* @param {string} name - the string identifier of the element
|
||||
* @see {@link SOGo.UIDesktop.sgFocusOn}
|
||||
*/
|
||||
.factory('sgFocus', ['$rootScope', '$timeout', function($rootScope, $timeout) {
|
||||
return function(name) {
|
||||
$timeout(function() {
|
||||
$rootScope.$broadcast('sgFocusOn', name);
|
||||
});
|
||||
}
|
||||
}])
|
||||
angular.module('SOGo.Common')
|
||||
|
||||
/*
|
||||
* sgFolderTree - Provides hierarchical folders tree
|
||||
* @memberof SOGo.UIDesktop
|
||||
* @memberof SOGo.Common
|
||||
* @restrict element
|
||||
* @param {object} sgRoot
|
||||
* @param {object} sgFolder
|
||||
* @param {function} sgSetFolder
|
||||
* @param {function} sgSelectFolder
|
||||
* @see https://github.com/marklagendijk/angular-recursion
|
||||
* @example:
|
||||
|
||||
|
@ -248,29 +29,30 @@
|
|||
folder: '=sgFolder',
|
||||
selectFolder: '=sgSelectFolder'
|
||||
},
|
||||
template:
|
||||
'<md-list-item>' +
|
||||
' <md-item-content layout="row" layout-align="start center" flex>' +
|
||||
' <i class="md-icon-folder"></i>' +
|
||||
' <button class="md-button md-flex sg-item-name">{{folder.name}}</button>' +
|
||||
template: [
|
||||
'<md-list-item>',
|
||||
' <md-item-content layout="row" layout-align="start center" flex>',
|
||||
' <i class="md-icon-folder"></i>',
|
||||
' <button class="md-button md-flex sg-item-name">{{folder.name}}</button>',
|
||||
' <md-input-container class="md-flex md-tile-content ng-hide">'+
|
||||
' <input type="text"' +
|
||||
' ng-model="folder.name"' +
|
||||
' ng-blur="save()"' +
|
||||
' sg-enter="save()"' +
|
||||
' sg-escape="revert()"/>' +
|
||||
' </md-input-container>' +
|
||||
' <span class="icon ng-hide" ng-cloak="ng-cloak">' +
|
||||
' <a class="icon" href="#"' +
|
||||
' dropdown-toggle="#folderProperties"' +
|
||||
' options="align:right"><i class="md-icon-more-vert"></i></a>' +
|
||||
' </span>' +
|
||||
' </md-item-content>' +
|
||||
'</md-list-item>' +
|
||||
'<sg-folder-tree ng-repeat="child in folder.children track by child.path"' +
|
||||
' data-sg-root="root"' +
|
||||
' data-sg-folder="child"' +
|
||||
' data-sg-select-folder="selectFolder"></sg-folder-tree>',
|
||||
' <input type="text"',
|
||||
' ng-model="folder.name"',
|
||||
' ng-blur="save()"',
|
||||
' sg-enter="save()"',
|
||||
' sg-escape="revert()"/>',
|
||||
' </md-input-container>',
|
||||
' <span class="icon ng-hide" ng-cloak="ng-cloak">',
|
||||
' <a class="icon" href="#"',
|
||||
' dropdown-toggle="#folderProperties"',
|
||||
' options="align:right"><i class="md-icon-more-vert"></i></a>',
|
||||
' </span>',
|
||||
' </md-item-content>',
|
||||
'</md-list-item>',
|
||||
'<sg-folder-tree ng-repeat="child in folder.children track by child.path"',
|
||||
' sg-root="root"',
|
||||
' sg-folder="child"',
|
||||
' sg-select-folder="selectFolder"></sg-folder-tree>'
|
||||
].join(''),
|
||||
compile: function(element) {
|
||||
return RecursionHelper.compile(element, function(scope, iElement, iAttrs, controller, transcludeFn) {
|
||||
var level, link, inputContainer, input, edit;
|
||||
|
@ -378,7 +160,7 @@
|
|||
|
||||
/*
|
||||
* sgDropdownContentToggle - Provides dropdown content functionality
|
||||
* @memberof SOGo.UIDesktop
|
||||
* @memberof SOGo.Common
|
||||
* @restrict class or attribute
|
||||
* @see https://github.com/pineconellc/angular-foundation/blob/master/src/dropdownToggle/dropdownToggle.js
|
||||
* @example:
|
||||
|
@ -496,57 +278,7 @@
|
|||
*/
|
||||
|
||||
/*
|
||||
* sgSubscribe - Common subscription widget
|
||||
* @restrict class or attribute
|
||||
* @param {String} sgSubscribe - the folder type
|
||||
* @param {Function} sgSubscribeOnSelect - the function to call when subscribing to a folder
|
||||
* @example:
|
||||
|
||||
<md-button sg-subscribe="contact" sg-subscribe-on-select="subscribeToFolder">Subscribe ..</md-button>
|
||||
*/
|
||||
.directive('sgSubscribe', [function() {
|
||||
console.debug('registering sgSubscribe');
|
||||
return {
|
||||
restrict: 'A',
|
||||
scope: {
|
||||
folderType: '@sgSubscribe',
|
||||
onFolderSelect: '&sgSubscribeOnSelect'
|
||||
},
|
||||
replace: false,
|
||||
bindToController: true,
|
||||
controllerAs: 'vm',
|
||||
controller: ['$scope', '$mdDialog', function($scope, $mdDialog) {
|
||||
var vm = this;
|
||||
vm.showDialog = function() {
|
||||
$mdDialog.show({
|
||||
templateUrl: '../Contacts/UIxContactsUserFolders',
|
||||
clickOutsideToClose: true,
|
||||
locals: {
|
||||
folderType: vm.folderType,
|
||||
onFolderSelect: vm.onFolderSelect
|
||||
},
|
||||
controller: function($scope, folderType, onFolderSelect) {
|
||||
$scope.selectUser = function(i) {
|
||||
// Fetch folders of specific type for selected user
|
||||
$scope.users[i].$folders(folderType).then(function() {
|
||||
$scope.selectedUser = $scope.users[i];
|
||||
});
|
||||
};
|
||||
$scope.selectFolder = function(folder) {
|
||||
onFolderSelect({folderData: folder});
|
||||
};
|
||||
}
|
||||
});
|
||||
};
|
||||
}],
|
||||
link: function(scope, element, attrs, controller) {
|
||||
element.on('click', controller.showDialog);
|
||||
}
|
||||
};
|
||||
}])
|
||||
|
||||
/*
|
||||
* sgUserTypeahead - Typeahead of users, used internally by sgSubscribe
|
||||
* UserTypeahead - Typeahead of users, used internally by sgSubscribe
|
||||
* @restrict attribute
|
||||
* @param {String} sgModel - the folder type
|
||||
* @param {Function} sgSubscribeOnSelect - the function to call when subscribing to a folder
|
||||
|
@ -555,7 +287,7 @@
|
|||
|
||||
<div sg-subscribe="contact" sg-subscribe-on-select="subscribeToFolder"></div>
|
||||
*/
|
||||
.directive('sgUserTypeahead', ['$parse', '$q', '$timeout', 'sgUser', function($parse, $q, $timeout, User) {
|
||||
.directive('sgUserTypeahead', ['$parse', '$q', '$timeout', 'User', function($parse, $q, $timeout, User) {
|
||||
return {
|
||||
restrict: 'A',
|
||||
require: 'ngModel',
|
||||
|
@ -648,272 +380,4 @@
|
|||
};
|
||||
}])
|
||||
|
||||
/*
|
||||
* sgSearch - Search within a list of items
|
||||
* @memberof SOGo.UIDesktop
|
||||
* @restrict attribute
|
||||
* @param {function} sgSearch - the function to call when performing a search.
|
||||
* Two variables are available: searchField and searchText.
|
||||
* @example:
|
||||
|
||||
<div sg-search="mailbox.$filter({ sort: 'date', asc: false }, [{ searchBy: searchField, searchInput: searchText }])">
|
||||
<md-input-container>
|
||||
<input name="search" type="search"/>
|
||||
</md-input-container>
|
||||
<md-select class="sg-toolbar-sort md-contrast-light">
|
||||
<md-option value="subject">Subject</md-option>
|
||||
<md-option value="sender">sender</md-option>
|
||||
</md-select>
|
||||
</div>
|
||||
*/
|
||||
.directive('sgSearch', ['$compile', function($compile) {
|
||||
return {
|
||||
restrict: 'A',
|
||||
controller: 'sgSearchController',
|
||||
controllerAs: '$sgSearchController',
|
||||
// See http://stackoverflow.com/questions/19224028/add-directives-from-directive-in-angularjs
|
||||
// for reasons of using terminal and priority
|
||||
terminal: true,
|
||||
priority: 1000,
|
||||
scope: {
|
||||
doSearch: '&sgSearch'
|
||||
},
|
||||
compile: compile
|
||||
};
|
||||
|
||||
function compile(tElement, tAttr) {
|
||||
var mdInputEl = tElement.find('md-input-container'),
|
||||
inputEl = tElement.find('input'),
|
||||
selectEl = tElement.find('md-select');
|
||||
|
||||
inputEl.attr('ng-model', '$sgSearchController.searchText');
|
||||
inputEl.attr('ng-model-options', '$sgSearchController.searchTextOptions');
|
||||
selectEl.attr('ng-model', '$sgSearchController.searchField');
|
||||
selectEl.attr('ng-change', '$sgSearchController.onChange()');
|
||||
|
||||
return function postLink(scope, iElement, iAttr, controller) {
|
||||
$compile(mdInputEl)(scope);
|
||||
$compile(selectEl)(scope);
|
||||
$compile(tElement.find('md-button'))(scope.$parent);
|
||||
|
||||
scope.$watch('$sgSearchController.searchText', angular.bind(controller, controller.onChange));
|
||||
}
|
||||
}
|
||||
}])
|
||||
.controller('sgSearchController', ['$scope', '$element', function($scope, $element) {
|
||||
// Controller variables
|
||||
this.previous = { searchText: '', searchField: '' };
|
||||
this.searchText = '';
|
||||
this.searchField = $element.find('md-option').attr('value'); // defaults to first option
|
||||
|
||||
// Model options
|
||||
this.searchTextOptions = {
|
||||
updateOn: 'default blur',
|
||||
debounce: {
|
||||
default: 300,
|
||||
blur: 0
|
||||
}
|
||||
};
|
||||
|
||||
// Method to call on data changes
|
||||
this.onChange = function(value) {
|
||||
if (typeof this.searchText != 'undefined') {
|
||||
if (this.searchText != this.previous.searchText || this.searchField != this.previous.searchField) {
|
||||
if (this.searchText.length > 2 || this.searchText.length == 0) {
|
||||
// See https://github.com/angular/angular.js/issues/7635
|
||||
// for why we need to use $scope here
|
||||
$scope.doSearch({ searchText: this.searchText, searchField: this.searchField });
|
||||
}
|
||||
this.previous = { searchText: this.searchText, searchField: this.searchField };
|
||||
}
|
||||
}
|
||||
};
|
||||
}])
|
||||
|
||||
/*
|
||||
* sgFolderStylesheet - Add CSS stylesheet for folder (addressbook or calendar)
|
||||
* @memberof SOGo.UIDesktop
|
||||
* @restrict attribute
|
||||
* @param {object} ngModel - the object literal describing the folder (an Addressbook or Calendar instance)
|
||||
* @example:
|
||||
|
||||
<div sg-folder-stylesheet="true"
|
||||
ng-repeat="calendar in calendars.list"
|
||||
ng-model="calendar" />
|
||||
</div>
|
||||
*/
|
||||
.directive('sgFolderStylesheet', [function() {
|
||||
return {
|
||||
restrict: 'A',
|
||||
require: 'ngModel',
|
||||
scope: {
|
||||
ngModel: '='
|
||||
},
|
||||
template: [
|
||||
'<style type="text/css">',
|
||||
' .bg-folder{{ ngModel.id }} {',
|
||||
' background-color: {{ ngModel.color }} !important;',
|
||||
' }',
|
||||
' .fg-folder{{ ngModel.id }} {',
|
||||
' color: {{ ngModel.color }} !important;',
|
||||
' }',
|
||||
' .checkbox-folder{{ ngModel.id }}.md-checked .md-icon {',
|
||||
' background-color: {{ ngModel.color }} !important;',
|
||||
' }',
|
||||
'</style>'
|
||||
].join('')
|
||||
}
|
||||
}])
|
||||
|
||||
/*
|
||||
* sgCalendarDayTable - Build list of blocks for a specific day
|
||||
* @memberof SOGo.UIDesktop
|
||||
* @restrict element
|
||||
* @param {object} sgBlocks - the events blocks definitions for the current view
|
||||
* @param {string} sgDay - the day of the events to display
|
||||
* @example:
|
||||
|
||||
<sg-calendar-day-table
|
||||
sg-blocks="calendar.blocks"
|
||||
sg-day="20150330" />
|
||||
*/
|
||||
.directive('sgCalendarDayTable', [function() {
|
||||
return {
|
||||
restrict: 'E',
|
||||
scope: {
|
||||
blocks: '=sgBlocks',
|
||||
day: '@sgDay'
|
||||
},
|
||||
template:
|
||||
'<sg-calendar-day-block class="event draggable"' +
|
||||
' ng-repeat="block in blocks[day]"' +
|
||||
' sg-block="block"/>',
|
||||
};
|
||||
}])
|
||||
|
||||
/*
|
||||
* sgCalendarDayBlock - An event block to be displayed in a week
|
||||
* @memberof SOGo.UIDesktop
|
||||
* @restrict element
|
||||
* @param {object} sgBlock - the event block definition
|
||||
* @example:
|
||||
|
||||
<sg-calendar-day-block
|
||||
ng-repeat="block in blocks[day]"
|
||||
sg-block="block"/>
|
||||
*/
|
||||
.directive('sgCalendarDayBlock', [function() {
|
||||
return {
|
||||
restrict: 'E',
|
||||
scope: {
|
||||
block: '=sgBlock'
|
||||
},
|
||||
replace: true,
|
||||
template: [
|
||||
'<div class="event draggable">',
|
||||
' <div class="eventInside">',
|
||||
' <div class="gradient">',
|
||||
' </div>',
|
||||
' <div class="text">{{ block.component.c_title }}',
|
||||
' <span class="icons">',
|
||||
' <i ng-if="block.component.c_nextalarm" class="md-icon-alarm"></i>',
|
||||
' <i ng-if="block.component.c_classification == 1" class="md-icon-visibility-off"></i>',
|
||||
' <i ng-if="block.component.c_classification == 2" class="md-icon-vpn-key"></i>',
|
||||
' </span></div>',
|
||||
' </div>',
|
||||
' <div class="topDragGrip"></div>',
|
||||
' <div class="bottomDragGrip"></div>',
|
||||
'</div>'
|
||||
].join(''),
|
||||
link: link
|
||||
};
|
||||
|
||||
function link(scope, iElement, attrs) {
|
||||
// Compute overlapping (5%)
|
||||
var pc = 100 / scope.block.siblings,
|
||||
left = scope.block.position * pc,
|
||||
right = 100 - (scope.block.position + 1) * pc;
|
||||
|
||||
if (pc < 100) {
|
||||
if (left > 0)
|
||||
left -= 5;
|
||||
if (right > 0)
|
||||
right -= 5;
|
||||
}
|
||||
|
||||
// Set position
|
||||
iElement.css('left', left + '%');
|
||||
iElement.css('right', right + '%');
|
||||
iElement.addClass('starts' + scope.block.start);
|
||||
iElement.addClass('lasts' + scope.block.length);
|
||||
iElement.addClass('bg-folder' + scope.block.component.c_folder);
|
||||
}
|
||||
}])
|
||||
|
||||
/*
|
||||
* sgCalendarMonthDay - Build list of blocks for a specific day in a month
|
||||
* @memberof SOGo.UIDesktop
|
||||
* @restrict element
|
||||
* @param {object} sgBlocks - the events blocks definitions for the current view
|
||||
* @param {string} sgDay - the day of the events to display
|
||||
* @example:
|
||||
|
||||
<sg-calendar-monh-day
|
||||
sg-blocks="calendar.blocks"
|
||||
sg-day="20150408" />
|
||||
*/
|
||||
.directive('sgCalendarMonthDay', [function() {
|
||||
return {
|
||||
restrict: 'E',
|
||||
scope: {
|
||||
blocks: '=sgBlocks',
|
||||
day: '@sgDay'
|
||||
},
|
||||
replace: true,
|
||||
template:
|
||||
'<sg-calendar-month-event' +
|
||||
' ng-repeat="block in blocks[day]"' +
|
||||
' sg-block="block"/>',
|
||||
};
|
||||
}])
|
||||
|
||||
/*
|
||||
* sgCalendarMonthEvent - An event block to be displayed in a month
|
||||
* @memberof SOGo.UIDesktop
|
||||
* @restrict element
|
||||
* @param {object} sgBlock - the event block definition
|
||||
* @example:
|
||||
|
||||
<sg-calendar-month-event
|
||||
ng-repeat="block in blocks[day]"
|
||||
sg-block="block"/>
|
||||
*/
|
||||
.directive('sgCalendarMonthEvent', [function() {
|
||||
return {
|
||||
restrict: 'E',
|
||||
scope: {
|
||||
block: '=sgBlock'
|
||||
},
|
||||
replace: true,
|
||||
template:
|
||||
'<div class="sg-event">' +
|
||||
' <span ng-if="!block.component.c_isallday">{{ block.starthour }} - </span>' +
|
||||
' {{ block.component.c_title }}' +
|
||||
' <span class="icons">' +
|
||||
' <i ng-if="block.component.c_nextalarm" class="md-icon-alarm"></i>' +
|
||||
' <i ng-if="block.component.c_classification == 1" class="md-icon-visibility-off"></i>' +
|
||||
' <i ng-if="block.component.c_classification == 2" class="md-icon-vpn-key"></i>' +
|
||||
' </span>' +
|
||||
' <div class="leftDragGrip"></div>' +
|
||||
' <div class="rightDragGrip"></div>' +
|
||||
' </div>' +
|
||||
'</div>',
|
||||
link: link
|
||||
};
|
||||
|
||||
function link(scope, iElement, attrs) {
|
||||
iElement.addClass('bg-folder' + scope.block.component.c_folder);
|
||||
}
|
||||
}]);
|
||||
|
||||
})();
|
||||
|
|
|
@ -1,161 +0,0 @@
|
|||
/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
|
||||
/**
|
||||
* The common SOGo UI, app module
|
||||
*
|
||||
* @type {angular.Module}
|
||||
*/
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
angular.module('SOGo.UI', ['ngMaterial', 'ngAnimate'])
|
||||
// md break-points values are hard-coded in angular-material/src/core/util/constant.js
|
||||
// $mdMedia has a built-in support for those values but can also evaluate others
|
||||
// For some reasons, angular-material's break-points don't match the specs
|
||||
// Here we define values according to specs
|
||||
.constant('sgConstant', {
|
||||
'sm': '(max-width: 600px)',
|
||||
'gt-sm': '(min-width: 600px)',
|
||||
'md': '(min-width: 600px) and (max-width: 1024px)',
|
||||
'gt-md': '(min-width: 1025px)',
|
||||
'lg': '(min-width: 1024px) and (max-width: 1280px)',
|
||||
'gt-lg': '(min-width: 1280px)'
|
||||
})
|
||||
|
||||
.config(['$mdThemingProvider', function ($mdThemingProvider) {
|
||||
|
||||
$mdThemingProvider.definePalette('sogo-green', {
|
||||
'50': 'eaf5e9',
|
||||
'100': 'cbe5c8',
|
||||
'200': 'aad6a5',
|
||||
'300': '88c781',
|
||||
'400': '66b86a',
|
||||
'500': '56b04c',
|
||||
'600': '4da143',
|
||||
'700': '388e3c',
|
||||
'800': '367d2e',
|
||||
'900': '225e1b',
|
||||
'A100': 'b9f6ca',
|
||||
'A200': '69f0ae',
|
||||
'A400': '00e676',
|
||||
'A700': '00c853',
|
||||
'contrastDefaultColor': 'dark',
|
||||
'contrastDarkColors': '50 100 200',
|
||||
'contrastLightColors': '300 400 500 600 700 800 900'
|
||||
});
|
||||
$mdThemingProvider.definePalette('sogo-blue', {
|
||||
'50': 'f0faf9',
|
||||
'100': 'e1f5f3',
|
||||
'200': 'ceebe8',
|
||||
'300': 'bfe0dd',
|
||||
'400': 'b2d6d3',
|
||||
'500': 'a1ccc8',
|
||||
'600': '8ebfbb',
|
||||
'700': '7db3b0',
|
||||
'800': '639997',
|
||||
'900': '4d8080',
|
||||
'A100': 'd4f7fa',
|
||||
'A200': 'c3f5fa',
|
||||
'A400': '53e3f0',
|
||||
'A700': '00b0c0',
|
||||
'contrastDefaultColor': 'light',
|
||||
'contrastDarkColors': ['50', '100', '200'],
|
||||
'contrastLightColors': ['300', '400', '500', '600', '700', '800', '900', 'A100', 'A200', 'A400', 'A700']
|
||||
});
|
||||
$mdThemingProvider.definePalette('sogo-paper', {
|
||||
'50': 'fcf7f8',
|
||||
'100': 'f7f1dc',
|
||||
'200': 'ede5ca',
|
||||
'300': 'e6d8ba',
|
||||
'400': 'e2d2a3',
|
||||
'500': 'd6c48d',
|
||||
'600': 'baa870',
|
||||
'700': '857545',
|
||||
'800': '524517',
|
||||
'900': '433809',
|
||||
'1000': '000000',
|
||||
'A100': 'ffffff',
|
||||
'A200': 'eeeeee',
|
||||
'A400': 'bdbdbd',
|
||||
'A700': '616161',
|
||||
'contrastDefaultColor': 'dark',
|
||||
'contrastLightColors': '800 900'
|
||||
});
|
||||
// Default theme definition
|
||||
// .primaryColor will soon be deprecated in favor of primaryPalette (already on dev builds https://groups.google.com/forum/m/#!topic/ngmaterial/-sXR8CYBMPg)
|
||||
$mdThemingProvider.theme('default')
|
||||
.primaryPalette('sogo-blue', {
|
||||
'default': '300',
|
||||
'hue-1': '100',
|
||||
'hue-2': '400',
|
||||
'hue-3': 'A700'
|
||||
})
|
||||
.accentPalette('sogo-green', {
|
||||
'default': '500',
|
||||
'hue-1': '200',
|
||||
'hue-2': '300',
|
||||
'hue-3': 'A700'
|
||||
})
|
||||
.backgroundPalette('sogo-paper', {
|
||||
'default': '100',
|
||||
'hue-1': '200',
|
||||
'hue-2': '50',
|
||||
'hue-3': '500'
|
||||
});
|
||||
}])
|
||||
|
||||
.filter('encodeUri', function ($window) {
|
||||
return $window.encodeURIComponent;
|
||||
})
|
||||
|
||||
.filter('decodeUri', function ($window) {
|
||||
return $window.decodeURIComponent;
|
||||
})
|
||||
|
||||
.filter('loc', function () {
|
||||
return l;
|
||||
})
|
||||
|
||||
.controller('navController', ['$scope', '$timeout', '$interval', '$http', '$mdSidenav', '$mdBottomSheet', '$mdMedia', '$log', 'sgConstant', function ($scope, $timeout, $interval, $http, $mdSidenav, $mdBottomSheet, $mdMedia, $log, sgConstant) {
|
||||
|
||||
// Show current day in top bar
|
||||
$scope.currentDay = window.currentDay;
|
||||
$timeout(function() {
|
||||
// Update date when day ends
|
||||
$interval(function() {
|
||||
$http.get('../date').success(function(data) {
|
||||
$scope.currentDay = data;
|
||||
});
|
||||
}, 24 * 3600 * 1000);
|
||||
}, window.secondsBeforeTomorrow * 1000);
|
||||
|
||||
$scope.toggleLeft = function () {
|
||||
$mdSidenav('left').toggle()
|
||||
.then(function () {
|
||||
$log.debug("toggle left is done");
|
||||
});
|
||||
};
|
||||
$scope.toggleRight = function () {
|
||||
$mdSidenav('right').toggle()
|
||||
.then(function () {
|
||||
$log.debug("toggle RIGHT is done");
|
||||
});
|
||||
};
|
||||
$scope.openBottomSheet = function() {
|
||||
$mdBottomSheet.show({
|
||||
parent: angular.element(document.getElementById('left-sidenav')),
|
||||
templateUrl: 'bottomSheetTemplate.html'
|
||||
});
|
||||
};
|
||||
$scope.toggleDetailView = function() {
|
||||
var detail = angular.element(document.getElementById('detailView'));
|
||||
detail.toggleClass('sg-close');
|
||||
};
|
||||
$scope.$watch(function() {
|
||||
return $mdMedia(sgConstant['gt-md']);
|
||||
},
|
||||
function(newVal) {
|
||||
$scope.isGtMedium = newVal;
|
||||
});
|
||||
}]);
|
||||
})();
|
|
@ -0,0 +1,112 @@
|
|||
/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* JavaScript for SOGoContacts */
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
angular.module('SOGo.Common', []);
|
||||
|
||||
angular.module('SOGo.ContactsUI', ['ngSanitize', 'ui.router', 'vs-repeat', 'SOGo.Common'])
|
||||
|
||||
.constant('sgSettings', {
|
||||
baseURL: ApplicationBaseURL,
|
||||
activeUser: {
|
||||
login: UserLogin,
|
||||
identification: UserIdentification,
|
||||
language: UserLanguage,
|
||||
folderURL: UserFolderURL,
|
||||
isSuperUser: IsSuperUser
|
||||
}
|
||||
})
|
||||
|
||||
.config(configure);
|
||||
|
||||
/**
|
||||
* @ngInject
|
||||
*/
|
||||
configure.$inject = ['$stateProvider', '$urlRouterProvider'];
|
||||
function configure($stateProvider, $urlRouterProvider) {
|
||||
$stateProvider
|
||||
.state('app', {
|
||||
url: '/addressbooks',
|
||||
abstract: true,
|
||||
views: {
|
||||
addressbooks: {
|
||||
templateUrl: 'UIxContactFoldersView', // UI/Templates/Contacts/UIxContactFoldersView.wox
|
||||
controller: 'AddressBooksController'
|
||||
}
|
||||
},
|
||||
resolve: {
|
||||
stateAddressbooks: ['AddressBook', function(AddressBook) {
|
||||
return AddressBook.$findAll(window.contactFolders);
|
||||
}]
|
||||
}
|
||||
})
|
||||
.state('app.addressbook', {
|
||||
url: '/:addressbookId',
|
||||
views: {
|
||||
addressbook: {
|
||||
templateUrl: 'addressbook',
|
||||
controller: 'AddressBookController'
|
||||
}
|
||||
},
|
||||
resolve: {
|
||||
stateAddressbook: ['$stateParams', 'AddressBook', function($stateParams, AddressBook) {
|
||||
return AddressBook.$find($stateParams.addressbookId);
|
||||
}]
|
||||
}
|
||||
})
|
||||
.state('app.addressbook.new', {
|
||||
url: '/{contactType:(?:card|list)}/new',
|
||||
views: {
|
||||
card: {
|
||||
templateUrl: 'UIxContactEditorTemplate', // UI/Templates/Contacts/UIxContactEditorTemplate.wox
|
||||
controller: 'CardController'
|
||||
}
|
||||
},
|
||||
resolve: {
|
||||
stateCard: ['$stateParams', 'stateAddressbook', 'Card', function($stateParams, stateAddressbook, Card) {
|
||||
var tag = 'v' + $stateParams.contactType,
|
||||
card = new Card({ pid: $stateParams.addressbookId, tag: tag });
|
||||
return card;
|
||||
}]
|
||||
}
|
||||
})
|
||||
.state('app.addressbook.card', {
|
||||
url: '/:cardId',
|
||||
abstract: true,
|
||||
views: {
|
||||
card: {
|
||||
template: '<ui-view/>'
|
||||
}
|
||||
},
|
||||
resolve: {
|
||||
stateCard: ['$stateParams', 'stateAddressbook', function($stateParams, stateAddressbook) {
|
||||
return stateAddressbook.$getCard($stateParams.cardId);
|
||||
}]
|
||||
}
|
||||
})
|
||||
.state('app.addressbook.card.view', {
|
||||
url: '/view',
|
||||
views: {
|
||||
'card@app.addressbook': {
|
||||
templateUrl: 'UIxContactViewTemplate', // UI/Templates/Contacts/UIxContactViewTemplate.wox
|
||||
controller: 'CardController'
|
||||
}
|
||||
}
|
||||
})
|
||||
.state('app.addressbook.card.editor', {
|
||||
url: '/edit',
|
||||
views: {
|
||||
'card@app.addressbook': {
|
||||
templateUrl: 'UIxContactEditorTemplate', // UI/Templates/Contacts/UIxContactEditorTemplate.wox
|
||||
controller: 'CardController'
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// if none of the above states are matched, use this as the fallback
|
||||
$urlRouterProvider.otherwise('/addressbooks/personal');
|
||||
}
|
||||
|
||||
})();
|
|
@ -32,7 +32,7 @@
|
|||
* @desc The factory we'll use to register with Angular
|
||||
* @returns the AddressBook constructor
|
||||
*/
|
||||
AddressBook.$factory = ['$q', '$timeout', '$log', 'sgSettings', 'sgResource', 'sgCard', 'sgAcl', function($q, $timeout, $log, Settings, Resource, Card, Acl) {
|
||||
AddressBook.$factory = ['$q', '$timeout', '$log', 'sgSettings', 'Resource', 'Card', 'Acl', function($q, $timeout, $log, Settings, Resource, Card, Acl) {
|
||||
angular.extend(AddressBook, {
|
||||
$q: $q,
|
||||
$timeout: $timeout,
|
||||
|
@ -48,7 +48,7 @@
|
|||
|
||||
/* Factory registration in Angular module */
|
||||
angular.module('SOGo.ContactsUI')
|
||||
.factory('sgAddressBook', AddressBook.$factory);
|
||||
.factory('AddressBook', AddressBook.$factory);
|
||||
|
||||
/**
|
||||
* @memberof AddressBook
|
|
@ -0,0 +1,56 @@
|
|||
/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* @ngInject
|
||||
*/
|
||||
AddressBookController.$inject = ['$state', '$scope', '$rootScope', '$stateParams', '$timeout', '$mdDialog', 'sgFocus', 'Card', 'AddressBook', 'Dialog', 'sgSettings', 'stateAddressbooks', 'stateAddressbook'];
|
||||
function AddressBookController($state, $scope, $rootScope, $stateParams, $timeout, $mdDialog, focus, Card, AddressBook, Dialog, Settings, stateAddressbooks, stateAddressbook) {
|
||||
var currentAddressbook;
|
||||
|
||||
$rootScope.currentFolder = stateAddressbook;
|
||||
|
||||
$scope.newComponent = function(ev) {
|
||||
$mdDialog.show({
|
||||
parent: angular.element(document.body),
|
||||
targetEvent: ev,
|
||||
clickOutsideToClose: true,
|
||||
escapeToClose: true,
|
||||
template: [
|
||||
'<md-dialog aria-label="Create component">',
|
||||
' <md-content>',
|
||||
' <div layout="column">',
|
||||
' <md-button ng-click="createContact()">',
|
||||
' ' + l('Contact'),
|
||||
' </md-button>',
|
||||
' <md-button ng-click="createList()">',
|
||||
' ' + l('List'),
|
||||
' </md-button>',
|
||||
' </div>',
|
||||
' </md-content>',
|
||||
'</md-dialog>'
|
||||
].join(''),
|
||||
locals: {
|
||||
state: $state
|
||||
},
|
||||
controller: ComponentDialogController
|
||||
});
|
||||
function ComponentDialogController(scope, $mdDialog, state) {
|
||||
scope.createContact = function() {
|
||||
state.go('app.addressbook.new', { addressbookId: $scope.currentFolder.id, contactType: 'card' });
|
||||
$mdDialog.hide();
|
||||
}
|
||||
scope.createList = function() {
|
||||
state.go('app.addressbook.new', { addressbookId: $scope.currentFolder.id, contactType: 'list' });
|
||||
$mdDialog.hide();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
angular
|
||||
.module('SOGo.ContactsUI')
|
||||
.controller('AddressBookController', AddressBookController);
|
||||
})();
|
|
@ -0,0 +1,183 @@
|
|||
/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* @ngInject
|
||||
*/
|
||||
AddressBooksController.$inject = ['$state', '$scope', '$rootScope', '$stateParams', '$timeout', '$q', '$mdDialog', 'sgFocus', 'Card', 'AddressBook', 'Dialog', 'sgSettings', 'User', 'stateAddressbooks'];
|
||||
function AddressBooksController($state, $scope, $rootScope, $stateParams, $timeout, $q, $mdDialog, focus, Card, AddressBook, Dialog, Settings, User, stateAddressbooks) {
|
||||
var currentAddressbook;
|
||||
|
||||
$scope.activeUser = Settings.activeUser;
|
||||
$scope.service = AddressBook;
|
||||
|
||||
// $scope functions
|
||||
$scope.select = function(folder) {
|
||||
$scope.editMode = false;
|
||||
$state.go('app.addressbook', {addressbookId: folder.id});
|
||||
};
|
||||
$scope.newAddressbook = function() {
|
||||
Dialog.prompt(l('New addressbook'),
|
||||
l('Name of new addressbook'))
|
||||
.then(function(name) {
|
||||
var addressbook = new AddressBook(
|
||||
{
|
||||
name: name,
|
||||
isEditable: true,
|
||||
isRemote: false,
|
||||
owner: UserLogin
|
||||
}
|
||||
);
|
||||
AddressBook.$add(addressbook);
|
||||
});
|
||||
};
|
||||
$scope.edit = function(index, folder) {
|
||||
if (!folder.isRemote) {
|
||||
$scope.editMode = folder.id;
|
||||
$scope.originalAddressbook = angular.extend({}, folder.$omit());
|
||||
focus('addressBookName_' + folder.id);
|
||||
}
|
||||
};
|
||||
$scope.revertEditing = function(folder) {
|
||||
folder.name = $scope.originalAddressbook.name;
|
||||
$scope.editMode = false;
|
||||
};
|
||||
$scope.save = function(folder) {
|
||||
var name = folder.name;
|
||||
if (name && name.length > 0 && name != $scope.originalAddressbook.name) {
|
||||
folder.$rename(name)
|
||||
.then(function(data) {
|
||||
$scope.editMode = false;
|
||||
}, function(data, status) {
|
||||
Dialog.alert(l('Warning'), data);
|
||||
});
|
||||
}
|
||||
};
|
||||
$scope.confirmDelete = function() {
|
||||
if ($scope.currentFolder.isSubscription) {
|
||||
// Unsubscribe without confirmation
|
||||
$rootScope.currentFolder.$delete()
|
||||
.then(function() {
|
||||
$rootScope.currentFolder = null;
|
||||
$state.go('app.addressbook', { addressbookId: 'personal' });
|
||||
}, function(data, status) {
|
||||
Dialog.alert(l('An error occured while deleting the addressbook "%{0}".',
|
||||
$rootScope.currentFolder.name),
|
||||
l(data.error));
|
||||
});
|
||||
}
|
||||
else {
|
||||
Dialog.confirm(l('Warning'), l('Are you sure you want to delete the addressbook <em>%{0}</em>?',
|
||||
$scope.currentFolder.name))
|
||||
.then(function() {
|
||||
$rootScope.currentFolder.$delete()
|
||||
.then(function() {
|
||||
$rootScope.currentFolder = null;
|
||||
}, function(data, status) {
|
||||
Dialog.alert(l('An error occured while deleting the addressbook "%{0}".',
|
||||
$rootScope.currentFolder.name),
|
||||
l(data.error));
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
$scope.importCards = function() {
|
||||
|
||||
};
|
||||
$scope.exportCards = function() {
|
||||
window.location.href = ApplicationBaseURL + '/' + $scope.currentFolder.id + '/exportFolder';
|
||||
};
|
||||
$scope.share = function(folder) {
|
||||
if (folder.id != $scope.currentFolder.id) {
|
||||
// Counter the possibility to click on the "hidden" secondary button
|
||||
$scope.select(folder);
|
||||
return;
|
||||
}
|
||||
$mdDialog.show({
|
||||
templateUrl: $scope.currentFolder.id + '/UIxAclEditor', // UI/Templates/UIxAclEditor.wox
|
||||
controller: AddressBookACLController,
|
||||
clickOutsideToClose: true,
|
||||
escapeToClose: true,
|
||||
locals: {
|
||||
usersWithACL: $scope.currentFolder.$acl.$users(),
|
||||
User: User,
|
||||
stateAddressbook: $scope.currentFolder,
|
||||
q: $q
|
||||
}
|
||||
});
|
||||
function AddressBookACLController($scope, $mdDialog, usersWithACL, User, stateAddressbook, q) {
|
||||
$scope.users = usersWithACL; // ACL users
|
||||
$scope.stateAddressbook = stateAddressbook;
|
||||
$scope.userToAdd = '';
|
||||
$scope.searchText = '';
|
||||
$scope.userFilter = function($query) {
|
||||
var deferred = q.defer();
|
||||
User.$filter($query).then(function(results) {
|
||||
deferred.resolve(results)
|
||||
});
|
||||
return deferred.promise;
|
||||
};
|
||||
$scope.closeModal = function() {
|
||||
stateAddressbook.$acl.$resetUsersRights(); // cancel changes
|
||||
$mdDialog.hide();
|
||||
};
|
||||
$scope.saveModal = function() {
|
||||
stateAddressbook.$acl.$saveUsersRights().then(function() {
|
||||
$mdDialog.hide();
|
||||
}, function(data, status) {
|
||||
Dialog.alert(l('Warning'), l('An error occured please try again.'));
|
||||
});
|
||||
};
|
||||
$scope.confirmChange = function(user) {
|
||||
var confirmation = user.$confirmRights();
|
||||
if (confirmation) {
|
||||
Dialog.confirm(l('Warning'), confirmation).then(function(res) {
|
||||
if (!res)
|
||||
user.$resetRights(true);
|
||||
});
|
||||
}
|
||||
};
|
||||
$scope.removeUser = function(user) {
|
||||
stateAddressbook.$acl.$removeUser(user.uid).then(function() {
|
||||
if (user.uid == $scope.selectedUser.uid) {
|
||||
$scope.selectedUser = null;
|
||||
}
|
||||
}, function(data, status) {
|
||||
Dialog.alert(l('Warning'), l('An error occured please try again.'))
|
||||
});
|
||||
};
|
||||
$scope.addUser = function(data) {
|
||||
stateAddressbook.$acl.$addUser(data).then(function() {
|
||||
$scope.userToAdd = '';
|
||||
$scope.searchText = '';
|
||||
}, function(error) {
|
||||
Dialog.alert(l('Warning'), error);
|
||||
});
|
||||
};
|
||||
$scope.selectUser = function(user) {
|
||||
// Check if it is a different user
|
||||
if ($scope.selectedUser != user) {
|
||||
$scope.selectedUser = user;
|
||||
$scope.selectedUser.$rights();
|
||||
}
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* subscribeToFolder - Callback of sgSubscribe directive
|
||||
*/
|
||||
$scope.subscribeToFolder = function(addressbookData) {
|
||||
console.debug('subscribeToFolder ' + addressbookData.owner + addressbookData.name);
|
||||
AddressBook.$subscribe(addressbookData.owner, addressbookData.name).catch(function(data) {
|
||||
Dialog.alert(l('Warning'), l('An error occured please try again.'));
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
angular
|
||||
.module('SOGo.ContactsUI')
|
||||
.controller('AddressBooksController', AddressBooksController);
|
||||
})();
|
|
@ -25,9 +25,6 @@
|
|||
|
||||
if (!this.shortFormat)
|
||||
this.shortFormat = this.$shortFormat();
|
||||
|
||||
// FIXME
|
||||
this.image = "http://www.gravatar.com/avatar/asdasdasdasd?d=identicon";
|
||||
}
|
||||
else {
|
||||
// The promise will be unwrapped first
|
||||
|
@ -45,7 +42,7 @@
|
|||
* @desc The factory we'll use to register with Angular.
|
||||
* @returns the Card constructor
|
||||
*/
|
||||
Card.$factory = ['$timeout', 'sgSettings', 'sgResource', function($timeout, Settings, Resource) {
|
||||
Card.$factory = ['$timeout', 'sgSettings', 'Resource', function($timeout, Settings, Resource) {
|
||||
angular.extend(Card, {
|
||||
$$resource: new Resource(Settings.activeUser.folderURL + 'Contacts', Settings.activeUser),
|
||||
$timeout: $timeout,
|
||||
|
@ -60,34 +57,7 @@
|
|||
* @desc Factory registration of Card in Angular module.
|
||||
*/
|
||||
angular.module('SOGo.ContactsUI')
|
||||
.factory('sgCard', Card.$factory)
|
||||
|
||||
/**
|
||||
* @name sgAddress
|
||||
* @memberof ContactsUI
|
||||
* @desc Directive to format a postal address.
|
||||
*/
|
||||
.directive('sgAddress', function() {
|
||||
return {
|
||||
restrict: 'A',
|
||||
scope: { data: '=sgAddress' },
|
||||
controller: ['$scope', function($scope) {
|
||||
$scope.addressLines = function(data) {
|
||||
var lines = [],
|
||||
locality_region = [];
|
||||
if (data.street) lines.push(data.street);
|
||||
if (data.street2) lines.push(data.street2);
|
||||
if (data.locality) locality_region.push(data.locality);
|
||||
if (data.region) locality_region.push(data.region);
|
||||
if (locality_region.length > 0) lines.push(locality_region.join(', '));
|
||||
if (data.country) lines.push(data.country);
|
||||
if (data.postalcode) lines.push(data.postalcode);
|
||||
return lines.join('<br>');
|
||||
};
|
||||
}],
|
||||
template: '<address ng-bind-html="addressLines(data)"></address>'
|
||||
}
|
||||
});
|
||||
.factory('Card', Card.$factory)
|
||||
|
||||
/**
|
||||
* @memberof Card
|
|
@ -0,0 +1,103 @@
|
|||
/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Controller to view and edit a card
|
||||
* @ngInject
|
||||
*/
|
||||
CardController.$inject = ['$scope', '$rootScope', '$timeout', 'AddressBook', 'Card', 'Dialog', 'sgFocus', '$state', '$stateParams', 'stateCard'];
|
||||
function CardController($scope, $rootScope, $timeout, AddressBook, Card, Dialog, focus, $state, $stateParams, stateCard) {
|
||||
$rootScope.card = stateCard;
|
||||
|
||||
$scope.allEmailTypes = Card.$EMAIL_TYPES;
|
||||
$scope.allTelTypes = Card.$TEL_TYPES;
|
||||
$scope.allUrlTypes = Card.$URL_TYPES;
|
||||
$scope.allAddressTypes = Card.$ADDRESS_TYPES;
|
||||
$scope.categories = {};
|
||||
|
||||
$scope.addOrgUnit = function() {
|
||||
var i = $scope.card.$addOrgUnit('');
|
||||
focus('orgUnit_' + i);
|
||||
};
|
||||
$scope.addEmail = function() {
|
||||
var i = $scope.card.$addEmail('');
|
||||
focus('email_' + i);
|
||||
};
|
||||
$scope.addPhone = function() {
|
||||
var i = $scope.card.$addPhone('');
|
||||
focus('phone_' + i);
|
||||
};
|
||||
$scope.addUrl = function() {
|
||||
var i = $scope.card.$addUrl('', '');
|
||||
focus('url_' + i);
|
||||
};
|
||||
$scope.addAddress = function() {
|
||||
var i = $scope.card.$addAddress('', '', '', '', '', '', '', '');
|
||||
focus('address_' + i);
|
||||
};
|
||||
$scope.addMember = function() {
|
||||
var i = $scope.card.$addMember('');
|
||||
focus('ref_' + i);
|
||||
};
|
||||
$scope.save = function(form) {
|
||||
if (form.$valid) {
|
||||
$scope.card.$save()
|
||||
.then(function(data) {
|
||||
var i = _.indexOf(_.pluck($scope.currentFolder.cards, 'id'), $scope.card.id);
|
||||
if (i < 0) {
|
||||
// New card; reload contacts list and show addressbook in which the card has been created
|
||||
$rootScope.currentFolder = AddressBook.$find(data.pid);
|
||||
}
|
||||
else {
|
||||
// Update contacts list with new version of the Card object
|
||||
$rootScope.currentFolder.cards[i] = angular.copy($scope.card);
|
||||
}
|
||||
$state.go('app.addressbook.card.view', { cardId: $scope.card.id });
|
||||
}, function(data, status) {
|
||||
console.debug('failed');
|
||||
});
|
||||
}
|
||||
};
|
||||
$scope.reset = function() {
|
||||
$scope.card.$reset();
|
||||
};
|
||||
$scope.cancel = function() {
|
||||
$scope.card.$reset();
|
||||
if ($scope.card.isNew) {
|
||||
// Cancelling the creation of a card
|
||||
$scope.card = null;
|
||||
$state.go('app.addressbook', { addressbookId: $scope.currentFolder.id });
|
||||
}
|
||||
else {
|
||||
// Cancelling the edition of an existing card
|
||||
$state.go('app.addressbook.card.view', { cardId: $scope.card.id });
|
||||
}
|
||||
};
|
||||
$scope.confirmDelete = function(card) {
|
||||
Dialog.confirm(l('Warning'),
|
||||
l('Are you sure you want to delete the card of %{0}?', card.$fullname()))
|
||||
.then(function() {
|
||||
// User confirmed the deletion
|
||||
card.$delete()
|
||||
.then(function() {
|
||||
// Remove card from list of addressbook
|
||||
$rootScope.currentFolder.cards = _.reject($rootScope.currentFolder.cards, function(o) {
|
||||
return o.id == card.id;
|
||||
});
|
||||
// Remove card object from scope
|
||||
$scope.card = null;
|
||||
$state.go('app.addressbook', { addressbookId: $scope.currentFolder.id });
|
||||
}, function(data, status) {
|
||||
Dialog.alert(l('Warning'), l('An error occured while deleting the card "%{0}".',
|
||||
card.$fullname()));
|
||||
});
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
angular
|
||||
.module('SOGo.ContactsUI')
|
||||
.controller('CardController', CardController);
|
||||
})();
|
|
@ -0,0 +1,37 @@
|
|||
/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* @name sgAddress
|
||||
* @memberof ContactsUI
|
||||
* @desc Directive to format a postal address.
|
||||
* @ngInject
|
||||
*/
|
||||
function sgAddress() {
|
||||
return {
|
||||
restrict: 'A',
|
||||
scope: { data: '=sgAddress' },
|
||||
controller: ['$scope', function($scope) {
|
||||
$scope.addressLines = function(data) {
|
||||
var lines = [],
|
||||
locality_region = [];
|
||||
if (data.street) lines.push(data.street);
|
||||
if (data.street2) lines.push(data.street2);
|
||||
if (data.locality) locality_region.push(data.locality);
|
||||
if (data.region) locality_region.push(data.region);
|
||||
if (locality_region.length > 0) lines.push(locality_region.join(', '));
|
||||
if (data.country) lines.push(data.country);
|
||||
if (data.postalcode) lines.push(data.postalcode);
|
||||
return lines.join('<br>');
|
||||
};
|
||||
}],
|
||||
template: '<address ng-bind-html="addressLines(data)"></address>'
|
||||
}
|
||||
}
|
||||
|
||||
angular
|
||||
.module('SOGo.Common')
|
||||
.directive('sgAddress', sgAddress);
|
||||
})();
|
|
@ -1,410 +0,0 @@
|
|||
/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* JavaScript for SOGoContacts */
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
angular.module('SOGo.Common', []);
|
||||
|
||||
angular.module('SOGo.ContactsUI', ['ngSanitize', 'ui.router', 'vs-repeat', 'SOGo.Common', 'SOGo.UI', 'SOGo.UIDesktop'])
|
||||
|
||||
.constant('sgSettings', {
|
||||
baseURL: ApplicationBaseURL,
|
||||
activeUser: {
|
||||
login: UserLogin,
|
||||
identification: UserIdentification,
|
||||
language: UserLanguage,
|
||||
folderURL: UserFolderURL,
|
||||
isSuperUser: IsSuperUser
|
||||
}
|
||||
})
|
||||
|
||||
.config(['$stateProvider', '$urlRouterProvider', function($stateProvider, $urlRouterProvider) {
|
||||
$stateProvider
|
||||
.state('app', {
|
||||
url: '/addressbooks',
|
||||
abstract: true,
|
||||
views: {
|
||||
addressbooks: {
|
||||
templateUrl: 'UIxContactFoldersView', // UI/Templates/Contacts/UIxContactFoldersView.wox
|
||||
controller: 'AddressBooksCtrl'
|
||||
}
|
||||
},
|
||||
resolve: {
|
||||
stateAddressbooks: ['sgAddressBook', function(AddressBook) {
|
||||
return AddressBook.$findAll(window.contactFolders);
|
||||
}]
|
||||
}
|
||||
})
|
||||
.state('app.addressbook', {
|
||||
url: '/:addressbookId',
|
||||
views: {
|
||||
addressbook: {
|
||||
templateUrl: 'addressbook',
|
||||
controller: 'AddressBookCtrl'
|
||||
}
|
||||
},
|
||||
resolve: {
|
||||
stateAddressbook: ['$stateParams', 'sgAddressBook', function($stateParams, AddressBook) {
|
||||
return AddressBook.$find($stateParams.addressbookId);
|
||||
}]
|
||||
}
|
||||
})
|
||||
.state('app.addressbook.new', {
|
||||
url: '/:contactType/new',
|
||||
views: {
|
||||
card: {
|
||||
templateUrl: 'UIxContactEditorTemplate', // UI/Templates/Contacts/UIxContactEditorTemplate.wox
|
||||
controller: 'CardCtrl'
|
||||
}
|
||||
},
|
||||
resolve: {
|
||||
stateCard: ['$stateParams', 'stateAddressbook', 'sgCard', function($stateParams, stateAddressbook, Card) {
|
||||
var tag = 'v' + $stateParams.contactType,
|
||||
card = new Card({ pid: $stateParams.addressbookId, tag: tag });
|
||||
return card;
|
||||
}]
|
||||
}
|
||||
})
|
||||
.state('app.addressbook.card', {
|
||||
url: '/:cardId',
|
||||
abstract: true,
|
||||
views: {
|
||||
card: {
|
||||
template: '<ui-view/>'
|
||||
}
|
||||
},
|
||||
resolve: {
|
||||
stateCard: ['$stateParams', 'stateAddressbook', function($stateParams, stateAddressbook) {
|
||||
return stateAddressbook.$getCard($stateParams.cardId);
|
||||
}]
|
||||
}
|
||||
})
|
||||
.state('app.addressbook.card.view', {
|
||||
url: '/view',
|
||||
views: {
|
||||
'card@app.addressbook': {
|
||||
templateUrl: 'UIxContactViewTemplate', // UI/Templates/Contacts/UIxContactViewTemplate.wox
|
||||
controller: 'CardCtrl'
|
||||
}
|
||||
}
|
||||
})
|
||||
.state('app.addressbook.card.editor', {
|
||||
url: '/edit',
|
||||
views: {
|
||||
'card@app.addressbook': {
|
||||
templateUrl: 'UIxContactEditorTemplate', // UI/Templates/Contacts/UIxContactEditorTemplate.wox
|
||||
controller: 'CardCtrl'
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// if none of the above states are matched, use this as the fallback
|
||||
$urlRouterProvider.otherwise('/addressbooks/personal');
|
||||
}])
|
||||
|
||||
.controller('AddressBooksCtrl', ['$state', '$scope', '$rootScope', '$stateParams', '$timeout', '$q', '$mdDialog', 'sgFocus', 'sgCard', 'sgAddressBook', 'sgDialog', 'sgSettings', 'sgUser', 'stateAddressbooks', function($state, $scope, $rootScope, $stateParams, $timeout, $q, $mdDialog, focus, Card, AddressBook, Dialog, Settings, User, stateAddressbooks) {
|
||||
var currentAddressbook;
|
||||
|
||||
$scope.activeUser = Settings.activeUser;
|
||||
$scope.service = AddressBook;
|
||||
|
||||
// $scope functions
|
||||
$scope.select = function(folder) {
|
||||
$scope.editMode = false;
|
||||
$rootScope.card = null;
|
||||
$state.go('app.addressbook', {addressbookId: folder.id});
|
||||
};
|
||||
$scope.newAddressbook = function() {
|
||||
Dialog.prompt(l('New addressbook'),
|
||||
l('Name of new addressbook'))
|
||||
.then(function(name) {
|
||||
var addressbook = new AddressBook(
|
||||
{
|
||||
name: name,
|
||||
isEditable: true,
|
||||
isRemote: false,
|
||||
owner: UserLogin
|
||||
}
|
||||
);
|
||||
AddressBook.$add(addressbook);
|
||||
});
|
||||
};
|
||||
$scope.edit = function(index, folder) {
|
||||
if (!folder.isRemote) {
|
||||
$scope.editMode = folder.id;
|
||||
$scope.originalAddressbook = angular.extend({}, folder.$omit());
|
||||
focus('addressBookName_' + folder.id);
|
||||
}
|
||||
};
|
||||
$scope.revertEditing = function(folder) {
|
||||
folder.name = $scope.originalAddressbook.name;
|
||||
$scope.editMode = false;
|
||||
};
|
||||
$scope.save = function(folder) {
|
||||
var name = folder.name;
|
||||
if (name && name.length > 0 && name != $scope.originalAddressbook.name) {
|
||||
folder.$rename(name)
|
||||
.then(function(data) {
|
||||
$scope.editMode = false;
|
||||
}, function(data, status) {
|
||||
Dialog.alert(l('Warning'), data);
|
||||
});
|
||||
}
|
||||
};
|
||||
$scope.confirmDelete = function() {
|
||||
if ($scope.currentFolder.isSubscription) {
|
||||
// Unsubscribe without confirmation
|
||||
$rootScope.currentFolder.$delete()
|
||||
.then(function() {
|
||||
$rootScope.currentFolder = null;
|
||||
$state.go('app.addressbook', { addressbookId: 'personal' });
|
||||
}, function(data, status) {
|
||||
Dialog.alert(l('An error occured while deleting the addressbook "%{0}".',
|
||||
$rootScope.currentFolder.name),
|
||||
l(data.error));
|
||||
});
|
||||
}
|
||||
else {
|
||||
Dialog.confirm(l('Warning'), l('Are you sure you want to delete the addressbook <em>%{0}</em>?',
|
||||
$scope.currentFolder.name))
|
||||
.then(function() {
|
||||
$rootScope.currentFolder.$delete()
|
||||
.then(function() {
|
||||
$rootScope.currentFolder = null;
|
||||
}, function(data, status) {
|
||||
Dialog.alert(l('An error occured while deleting the addressbook "%{0}".',
|
||||
$rootScope.currentFolder.name),
|
||||
l(data.error));
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
$scope.importCards = function() {
|
||||
|
||||
};
|
||||
$scope.exportCards = function() {
|
||||
window.location.href = ApplicationBaseURL + '/' + $scope.currentFolder.id + '/exportFolder';
|
||||
};
|
||||
$scope.share = function(folder) {
|
||||
if (folder.id != $scope.currentFolder.id) {
|
||||
// Counter the possibility to click on the "hidden" secondary button
|
||||
$scope.select(folder);
|
||||
return;
|
||||
}
|
||||
$mdDialog.show({
|
||||
templateUrl: $scope.currentFolder.id + '/UIxAclEditor', // UI/Templates/UIxAclEditor.wox
|
||||
controller: AddressBookACLController,
|
||||
clickOutsideToClose: true,
|
||||
escapeToClose: true,
|
||||
locals: {
|
||||
usersWithACL: $scope.currentFolder.$acl.$users(),
|
||||
User: User,
|
||||
stateAddressbook: $scope.currentFolder,
|
||||
q: $q
|
||||
}
|
||||
});
|
||||
function AddressBookACLController($scope, $mdDialog, usersWithACL, User, stateAddressbook, q) {
|
||||
$scope.users = usersWithACL; // ACL users
|
||||
$scope.stateAddressbook = stateAddressbook;
|
||||
$scope.userToAdd = '';
|
||||
$scope.searchText = '';
|
||||
$scope.userFilter = function($query) {
|
||||
var deferred = q.defer();
|
||||
User.$filter($query).then(function(results) {
|
||||
deferred.resolve(results)
|
||||
});
|
||||
return deferred.promise;
|
||||
};
|
||||
$scope.closeModal = function() {
|
||||
stateAddressbook.$acl.$resetUsersRights(); // cancel changes
|
||||
$mdDialog.hide();
|
||||
};
|
||||
$scope.saveModal = function() {
|
||||
stateAddressbook.$acl.$saveUsersRights().then(function() {
|
||||
$mdDialog.hide();
|
||||
}, function(data, status) {
|
||||
Dialog.alert(l('Warning'), l('An error occured please try again.'));
|
||||
});
|
||||
};
|
||||
$scope.confirmChange = function(user) {
|
||||
var confirmation = user.$confirmRights();
|
||||
if (confirmation) {
|
||||
Dialog.confirm(l('Warning'), confirmation).then(function(res) {
|
||||
if (!res)
|
||||
user.$resetRights(true);
|
||||
});
|
||||
}
|
||||
};
|
||||
$scope.removeUser = function(user) {
|
||||
stateAddressbook.$acl.$removeUser(user.uid).then(function() {
|
||||
if (user.uid == $scope.selectedUser.uid) {
|
||||
$scope.selectedUser = null;
|
||||
}
|
||||
}, function(data, status) {
|
||||
Dialog.alert(l('Warning'), l('An error occured please try again.'))
|
||||
});
|
||||
};
|
||||
$scope.addUser = function(data) {
|
||||
stateAddressbook.$acl.$addUser(data).then(function() {
|
||||
$scope.userToAdd = '';
|
||||
$scope.searchText = '';
|
||||
}, function(error) {
|
||||
Dialog.alert(l('Warning'), error);
|
||||
});
|
||||
};
|
||||
$scope.selectUser = function(user) {
|
||||
// Check if it is a different user
|
||||
if ($scope.selectedUser != user) {
|
||||
$scope.selectedUser = user;
|
||||
$scope.selectedUser.$rights();
|
||||
}
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* subscribeToFolder - Callback of sgSubscribe directive
|
||||
*/
|
||||
$scope.subscribeToFolder = function(addressbookData) {
|
||||
console.debug('subscribeToFolder ' + addressbookData.owner + addressbookData.name);
|
||||
AddressBook.$subscribe(addressbookData.owner, addressbookData.name).catch(function(data) {
|
||||
Dialog.alert(l('Warning'), l('An error occured please try again.'));
|
||||
});
|
||||
};
|
||||
}])
|
||||
|
||||
.controller('AddressBookCtrl', ['$state', '$scope', '$rootScope', '$stateParams', '$timeout', '$mdDialog', 'sgFocus', 'sgCard', 'sgAddressBook', 'sgDialog', 'sgSettings', 'stateAddressbooks', 'stateAddressbook', function($state, $scope, $rootScope, $stateParams, $timeout, $mdDialog, focus, Card, AddressBook, Dialog, Settings, stateAddressbooks, stateAddressbook) {
|
||||
var currentAddressbook;
|
||||
|
||||
$rootScope.currentFolder = stateAddressbook;
|
||||
|
||||
$scope.newComponent = function(ev) {
|
||||
$mdDialog.show({
|
||||
parent: angular.element(document.body),
|
||||
targetEvent: ev,
|
||||
clickOutsideToClose: true,
|
||||
escapeToClose: true,
|
||||
template:
|
||||
'<md-dialog aria-label="Create component">' +
|
||||
' <md-content>' +
|
||||
' <div layout="column">' +
|
||||
' <md-button ng-click="createContact()">' +
|
||||
' Contact' +
|
||||
' </md-button>' +
|
||||
' <md-button ng-click="createList()">' +
|
||||
' List' +
|
||||
' </md-button>' +
|
||||
' </div>' +
|
||||
' </md-content>' +
|
||||
'</md-dialog>',
|
||||
locals: {
|
||||
state: $state
|
||||
},
|
||||
controller: ComponentDialogController
|
||||
});
|
||||
function ComponentDialogController(scope, $mdDialog, state) {
|
||||
scope.createContact = function() {
|
||||
state.go('app.addressbook.new', { addressbookId: $scope.currentFolder.id, contactType: 'card' });
|
||||
$mdDialog.hide();
|
||||
}
|
||||
scope.createList = function() {
|
||||
state.go('app.addressbook.new', { addressbookId: $scope.currentFolder.id, contactType: 'list' });
|
||||
$mdDialog.hide();
|
||||
}
|
||||
}
|
||||
};
|
||||
}])
|
||||
|
||||
/**
|
||||
* Controller to view and edit a card
|
||||
*/
|
||||
.controller('CardCtrl', ['$scope', '$rootScope', '$timeout', 'sgAddressBook', 'sgCard', 'sgDialog', 'sgFocus', '$state', '$stateParams', 'stateCard', function($scope, $rootScope, $timeout, AddressBook, Card, Dialog, focus, $state, $stateParams, stateCard) {
|
||||
$rootScope.card = stateCard;
|
||||
|
||||
$scope.allEmailTypes = Card.$EMAIL_TYPES;
|
||||
$scope.allTelTypes = Card.$TEL_TYPES;
|
||||
$scope.allUrlTypes = Card.$URL_TYPES;
|
||||
$scope.allAddressTypes = Card.$ADDRESS_TYPES;
|
||||
$scope.categories = {};
|
||||
|
||||
$scope.addOrgUnit = function() {
|
||||
var i = $scope.card.$addOrgUnit('');
|
||||
focus('orgUnit_' + i);
|
||||
};
|
||||
$scope.addEmail = function() {
|
||||
var i = $scope.card.$addEmail('');
|
||||
focus('email_' + i);
|
||||
};
|
||||
$scope.addPhone = function() {
|
||||
var i = $scope.card.$addPhone('');
|
||||
focus('phone_' + i);
|
||||
};
|
||||
$scope.addUrl = function() {
|
||||
var i = $scope.card.$addUrl('', '');
|
||||
focus('url_' + i);
|
||||
};
|
||||
$scope.addAddress = function() {
|
||||
var i = $scope.card.$addAddress('', '', '', '', '', '', '', '');
|
||||
focus('address_' + i);
|
||||
};
|
||||
$scope.addMember = function() {
|
||||
var i = $scope.card.$addMember('');
|
||||
focus('ref_' + i);
|
||||
};
|
||||
$scope.save = function(form) {
|
||||
if (form.$valid) {
|
||||
$scope.card.$save()
|
||||
.then(function(data) {
|
||||
var i = _.indexOf(_.pluck($scope.currentFolder.cards, 'id'), $scope.card.id);
|
||||
if (i < 0) {
|
||||
// New card; reload contacts list and show addressbook in which the card has been created
|
||||
$rootScope.currentFolder = AddressBook.$find(data.pid);
|
||||
}
|
||||
else {
|
||||
// Update contacts list with new version of the Card object
|
||||
$rootScope.currentFolder.cards[i] = angular.copy($scope.card);
|
||||
}
|
||||
$state.go('app.addressbook.card.view', { cardId: $scope.card.id });
|
||||
}, function(data, status) {
|
||||
console.debug('failed');
|
||||
});
|
||||
}
|
||||
};
|
||||
$scope.reset = function() {
|
||||
$scope.card.$reset();
|
||||
};
|
||||
$scope.cancel = function() {
|
||||
$scope.card.$reset();
|
||||
if ($scope.card.isNew) {
|
||||
// Cancelling the creation of a card
|
||||
$scope.card = null;
|
||||
$state.go('app.addressbook', { addressbookId: $scope.currentFolder.id });
|
||||
}
|
||||
else {
|
||||
// Cancelling the edition of an existing card
|
||||
$state.go('app.addressbook.card.view', { cardId: $scope.card.id });
|
||||
}
|
||||
};
|
||||
$scope.confirmDelete = function(card) {
|
||||
Dialog.confirm(l('Warning'),
|
||||
l('Are you sure you want to delete the card of %{0}?', card.$fullname()))
|
||||
.then(function() {
|
||||
// User confirmed the deletion
|
||||
card.$delete()
|
||||
.then(function() {
|
||||
// Remove card from list of addressbook
|
||||
$rootScope.currentFolder.cards = _.reject($rootScope.currentFolder.cards, function(o) {
|
||||
return o.id == card.id;
|
||||
});
|
||||
// Remove card object from scope
|
||||
$scope.card = null;
|
||||
$state.go('app.addressbook', { addressbookId: $scope.currentFolder.id });
|
||||
}, function(data, status) {
|
||||
Dialog.alert(l('Warning'), l('An error occured while deleting the card "%{0}".',
|
||||
card.$fullname()));
|
||||
});
|
||||
});
|
||||
};
|
||||
}]);
|
||||
})();
|
|
@ -0,0 +1,185 @@
|
|||
/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* JavaScript for SOGo.MailerUI module */
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
angular.module('SOGo.ContactsUI', []);
|
||||
|
||||
angular.module('SOGo.MailerUI', ['ngSanitize', 'ui.router', 'vs-repeat', 'ck', 'angularFileUpload', 'SOGo.Common', 'SOGo.ContactsUI', 'ngAnimate'])
|
||||
|
||||
.constant('sgSettings', {
|
||||
baseURL: ApplicationBaseURL,
|
||||
activeUser: {
|
||||
login: UserLogin,
|
||||
identification: UserIdentification,
|
||||
language: UserLanguage,
|
||||
folderURL: UserFolderURL,
|
||||
isSuperUser: IsSuperUser
|
||||
}
|
||||
})
|
||||
|
||||
.config(configure)
|
||||
.run(runBlock);
|
||||
|
||||
/**
|
||||
* @ngInject
|
||||
*/
|
||||
configure.$inject = ['$stateProvider', '$urlRouterProvider'];
|
||||
function configure($stateProvider, $urlRouterProvider) {
|
||||
$stateProvider
|
||||
.state('mail', {
|
||||
url: '/Mail',
|
||||
views: {
|
||||
mailboxes: {
|
||||
templateUrl: 'UIxMailMainFrame', // UI/Templates/MailerUI/UIxMailMainFrame.wox
|
||||
controller: 'MailboxesController'
|
||||
}
|
||||
},
|
||||
resolve: {
|
||||
stateAccounts: ['$q', 'Account', function($q, Account) {
|
||||
var accounts = Account.$findAll(mailAccounts);
|
||||
var promises = [];
|
||||
// Fetch list of mailboxes for each account
|
||||
angular.forEach(accounts, function(account, i) {
|
||||
var mailboxes = account.$getMailboxes();
|
||||
promises.push(mailboxes.then(function(objects) {
|
||||
return account;
|
||||
}));
|
||||
});
|
||||
return $q.all(promises);
|
||||
}]
|
||||
}
|
||||
})
|
||||
.state('mail.account', {
|
||||
url: '/:accountId',
|
||||
abstract: true,
|
||||
views: {
|
||||
mailbox: {
|
||||
template: '<ui-view/>',
|
||||
}
|
||||
},
|
||||
resolve: {
|
||||
stateAccount: ['$stateParams', 'stateAccounts', function($stateParams, stateAccounts) {
|
||||
return _.find(stateAccounts, function(account) {
|
||||
return account.id == $stateParams.accountId;
|
||||
});
|
||||
}]
|
||||
}
|
||||
})
|
||||
.state('mail.account.mailbox', {
|
||||
url: '/:mailboxId',
|
||||
views: {
|
||||
'mailbox@mail': {
|
||||
templateUrl: 'UIxMailFolderTemplate', // UI/Templates/MailerUI/UIxMailFolderTemplate.wox
|
||||
controller: 'MailboxController'
|
||||
}
|
||||
},
|
||||
resolve: {
|
||||
stateMailbox: ['$stateParams', 'stateAccount', 'decodeUriFilter', function($stateParams, stateAccount, decodeUriFilter) {
|
||||
var mailboxId = decodeUriFilter($stateParams.mailboxId);
|
||||
// Recursive find function
|
||||
var _find = function(mailboxes) {
|
||||
var mailbox = _.find(mailboxes, function(o) {
|
||||
return o.path == mailboxId;
|
||||
});
|
||||
if (!mailbox) {
|
||||
angular.forEach(mailboxes, function(o) {
|
||||
if (!mailbox && o.children && o.children.length > 0) {
|
||||
mailbox = _find(o.children);
|
||||
}
|
||||
});
|
||||
}
|
||||
return mailbox;
|
||||
};
|
||||
return _find(stateAccount.$mailboxes);
|
||||
}],
|
||||
stateMessages: ['stateMailbox', function(stateMailbox) {
|
||||
return stateMailbox.$filter();
|
||||
}]
|
||||
}
|
||||
})
|
||||
.state('mail.account.mailbox.message', {
|
||||
url: '/:messageId',
|
||||
views: {
|
||||
message: {
|
||||
templateUrl: 'UIxMailViewTemplate', // UI/Templates/MailerUI/UIxMailViewTemplate.wox
|
||||
controller: 'MessageController'
|
||||
}
|
||||
},
|
||||
resolve: {
|
||||
stateMessage: ['encodeUriFilter', '$stateParams', '$state', 'stateMailbox', 'stateMessages', function(encodeUriFilter, $stateParams, $state, stateMailbox, stateMessages) {
|
||||
var message = _.find(stateMessages, function(messageObject) {
|
||||
return messageObject.uid == $stateParams.messageId;
|
||||
});
|
||||
|
||||
if (message)
|
||||
return message.$reload();
|
||||
else
|
||||
// Message not found
|
||||
$state.go('mail.account.mailbox', { accountId: stateMailbox.$account.id, mailboxId: encodeUriFilter(stateMailbox.path) });
|
||||
}]
|
||||
}
|
||||
})
|
||||
.state('mail.account.mailbox.message.edit', {
|
||||
url: '/edit',
|
||||
views: {
|
||||
'mailbox@mail': {
|
||||
templateUrl: 'UIxMailEditor', // UI/Templates/MailerUI/UIxMailEditor.wox
|
||||
controller: 'MessageEditorController'
|
||||
}
|
||||
},
|
||||
resolve: {
|
||||
stateContent: ['stateMessage', function(stateMessage) {
|
||||
return stateMessage.$editableContent();
|
||||
}]
|
||||
}
|
||||
})
|
||||
.state('mail.account.mailbox.message.action', {
|
||||
url: '/{actionName:(?:reply|replyall|forward)}',
|
||||
views: {
|
||||
'mailbox@mail': {
|
||||
templateUrl: 'UIxMailEditor', // UI/Templates/MailerUI/UIxMailEditor.wox
|
||||
controller: 'MessageEditorController'
|
||||
}
|
||||
}
|
||||
})
|
||||
.state('mail.newMessage', {
|
||||
url: '/new',
|
||||
views: {
|
||||
mailbox: {
|
||||
templateUrl: 'UIxMailEditor', // UI/Templates/MailerUI/UIxMailEditor.wox
|
||||
controller: 'MessageEditorController'
|
||||
}
|
||||
},
|
||||
resolve: {
|
||||
stateMessage: ['stateAccounts', function(stateAccounts) {
|
||||
if (stateAccounts.length > 0) {
|
||||
return stateAccounts[0].$newMessage();
|
||||
}
|
||||
}]
|
||||
}
|
||||
});
|
||||
|
||||
// if none of the above states are matched, use this as the fallback
|
||||
$urlRouterProvider.otherwise('/Mail');
|
||||
|
||||
// Set default configuration for tags input
|
||||
// tagsInputConfigProvider.setDefaults('tagsInput', {
|
||||
// addOnComma: false,
|
||||
// replaceSpacesWithDashes: false,
|
||||
// allowedTagsPattern: /([\w\!\#$\%\&\'\*\+\-\/\=\?\^\`{\|\}\~]+\.)*[\w\!\#$\%\&\'\*\+\-\/\=\?\^\`{\|\}\~]+@((((([a-z0-9]{1}[a-z0-9\-]{0,62}[a-z0-9]{1})|[a-z])\.)+[a-z]{2,})|(\d{1,3}\.){3}\d{1,3}(\:\d{1,5})?)/i
|
||||
// });
|
||||
}
|
||||
|
||||
/**
|
||||
* @ngInject
|
||||
*/
|
||||
runBlock.$inject = ['$rootScope'];
|
||||
function runBlock($rootScope) {
|
||||
$rootScope.$on('$routeChangeError', function(event, current, previous, rejection) {
|
||||
console.error(event, current, previous, rejection)
|
||||
})
|
||||
}
|
||||
|
||||
})();
|
|
@ -31,7 +31,7 @@
|
|||
* @desc The factory we'll use to register with Angular
|
||||
* @returns the Account constructor
|
||||
*/
|
||||
Account.$factory = ['$q', '$timeout', '$log', 'sgSettings', 'sgResource', 'sgMailbox', 'sgMessage', function($q, $timeout, $log, Settings, Resource, Mailbox, Message) {
|
||||
Account.$factory = ['$q', '$timeout', '$log', 'sgSettings', 'Resource', 'Mailbox', 'Message', function($q, $timeout, $log, Settings, Resource, Mailbox, Message) {
|
||||
angular.extend(Account, {
|
||||
$q: $q,
|
||||
$timeout: $timeout,
|
||||
|
@ -46,7 +46,7 @@
|
|||
|
||||
/* Factory registration in Angular module */
|
||||
angular.module('SOGo.MailerUI')
|
||||
.factory('sgAccount', Account.$factory);
|
||||
.factory('Account', Account.$factory);
|
||||
|
||||
/**
|
||||
* @memberof Account
|
||||
|
@ -70,7 +70,7 @@
|
|||
* @function $getMailboxes
|
||||
* @memberof Account.prototype
|
||||
* @desc Fetch the list of mailboxes for the current account.
|
||||
* @param {object} [options] - force a reload
|
||||
* @param {object} [options] - force a reload by setting 'reload' to true
|
||||
* @returns a promise of the HTTP operation
|
||||
*/
|
||||
Account.prototype.$getMailboxes = function(options) {
|
|
@ -9,6 +9,7 @@
|
|||
* @param {object} futureMailboxData - either an object literal or a promise
|
||||
*/
|
||||
function Mailbox(account, futureMailboxData) {
|
||||
this.$isLoading = false;
|
||||
this.$account = account;
|
||||
// Data is immediately available
|
||||
if (typeof futureMailboxData.then !== 'function') {
|
||||
|
@ -37,7 +38,7 @@
|
|||
* @desc The factory we'll use to register with Angular
|
||||
* @returns the Mailbox constructor
|
||||
*/
|
||||
Mailbox.$factory = ['$q', '$timeout', '$log', 'sgSettings', 'sgResource', 'sgMessage', 'sgMailbox_PRELOAD', function($q, $timeout, $log, Settings, Resource, Message, PRELOAD) {
|
||||
Mailbox.$factory = ['$q', '$timeout', '$log', 'sgSettings', 'Resource', 'Message', 'sgMailbox_PRELOAD', function($q, $timeout, $log, Settings, Resource, Message, PRELOAD) {
|
||||
angular.extend(Mailbox, {
|
||||
$q: $q,
|
||||
$timeout: $timeout,
|
||||
|
@ -61,7 +62,7 @@
|
|||
SIZE: 100
|
||||
})
|
||||
/* Factory registration in Angular module */
|
||||
.factory('sgMailbox', Mailbox.$factory);
|
||||
.factory('Mailbox', Mailbox.$factory);
|
||||
|
||||
/**
|
||||
* @memberof Mailbox
|
||||
|
@ -180,6 +181,7 @@
|
|||
});
|
||||
}
|
||||
|
||||
this.$isLoading = true;
|
||||
futureMailboxData = Mailbox.$$resource.post(this.id, 'view', options);
|
||||
|
||||
return this.$unwrap(futureMailboxData);
|
||||
|
@ -388,7 +390,7 @@
|
|||
|
||||
/**
|
||||
* @function $newMailbox
|
||||
* @memberof Account.prototype
|
||||
* @memberof Mailbox.prototype
|
||||
* @desc Create a new mailbox on the server and refresh the list of mailboxes.
|
||||
* @returns a promise of the HTTP operations
|
||||
*/
|
||||
|
@ -435,6 +437,8 @@
|
|||
_this.uidsMap = {};
|
||||
|
||||
if (_this.uids) {
|
||||
Mailbox.$log.debug('unwrapping ' + data.uids.length + ' messages');
|
||||
|
||||
// First entry of 'headers' are keys
|
||||
headers = _.invoke(_this.headers[0], 'toLowerCase');
|
||||
_this.headers.splice(0, 1);
|
||||
|
@ -469,6 +473,7 @@
|
|||
});
|
||||
}
|
||||
Mailbox.$log.debug('mailbox ' + _this.id + ' ready');
|
||||
_this.$isLoading = false;
|
||||
deferred.resolve(_this.$messages);
|
||||
});
|
||||
}, function(data) {
|
|
@ -0,0 +1,20 @@
|
|||
/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* @ngInject
|
||||
*/
|
||||
MailboxController.$inject = ['$scope', '$rootScope', '$stateParams', 'stateAccount', 'stateMailbox', '$timeout', 'sgFocus', 'Dialog', 'Account', 'Mailbox'];
|
||||
function MailboxController($scope, $rootScope, $stateParams, stateAccount, stateMailbox, $timeout, focus, Dialog, Account, Mailbox) {
|
||||
$scope.account = stateAccount;
|
||||
$rootScope.mailbox = stateMailbox;
|
||||
$rootScope.currentFolder = stateMailbox;
|
||||
}
|
||||
|
||||
angular
|
||||
.module('SOGo.MailerUI')
|
||||
.controller('MailboxController', MailboxController);
|
||||
})();
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* @ngInject
|
||||
*/
|
||||
MailboxesController.$inject = ['$scope', '$rootScope', '$stateParams', '$state', '$timeout', 'sgFocus', 'encodeUriFilter', 'Dialog', 'sgSettings', 'Account', 'Mailbox', 'stateAccounts'];
|
||||
function MailboxesController($scope, $rootScope, $stateParams, $state, $timeout, focus, encodeUriFilter, Dialog, Settings, Account, Mailbox, stateAccounts) {
|
||||
$scope.activeUser = Settings.activeUser;
|
||||
$scope.accounts = stateAccounts;
|
||||
|
||||
$scope.newFolder = function(parentFolder) {
|
||||
Dialog.prompt(l('New folder'),
|
||||
l('Enter the new name of your folder :'))
|
||||
.then(function(name) {
|
||||
parentFolder.$newMailbox(parentFolder.id, name);
|
||||
});
|
||||
};
|
||||
$scope.editFolder = function(folder) {
|
||||
$scope.editMode = folder.path;
|
||||
focus('mailboxName_' + folder.path);
|
||||
};
|
||||
$scope.revertEditing = function(folder) {
|
||||
folder.$reset();
|
||||
$scope.editMode = false;
|
||||
};
|
||||
$scope.selectFolder = function(account, folder) {
|
||||
if ($scope.editMode == folder.path)
|
||||
return;
|
||||
$rootScope.currentFolder = folder;
|
||||
$scope.editMode = false;
|
||||
$rootScope.message = null;
|
||||
$state.go('mail.account.mailbox', { accountId: account.id, mailboxId: encodeUriFilter(folder.path) });
|
||||
};
|
||||
$scope.saveFolder = function(folder) {
|
||||
folder.$rename();
|
||||
};
|
||||
$scope.exportMails = function() {
|
||||
window.location.href = ApplicationBaseURL + '/' + $rootScope.currentFolder.id + '/exportFolder';
|
||||
};
|
||||
$scope.confirmDelete = function(folder) {
|
||||
if (folder.path != $scope.currentFolder.path) {
|
||||
// Counter the possibility to click on the "hidden" secondary button
|
||||
$scope.selectFolder(folder.$account, folder);
|
||||
return;
|
||||
}
|
||||
Dialog.confirm(l('Confirmation'), l('Do you really want to move this folder into the trash ?'))
|
||||
.then(function() {
|
||||
folder.$delete()
|
||||
.then(function() {
|
||||
$rootScope.currentFolder = null;
|
||||
$state.go('mail');
|
||||
}, function(data, status) {
|
||||
Dialog.alert(l('An error occured while deleting the mailbox "%{0}".', folder.name),
|
||||
l(data.error));
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
if ($state.current.name == 'mail' && $scope.accounts.length > 0 && $scope.accounts[0].$mailboxes.length > 0) {
|
||||
// Redirect to first mailbox of first account if no mailbox is selected
|
||||
var account = $scope.accounts[0];
|
||||
var mailbox = account.$mailboxes[0];
|
||||
$state.go('mail.account.mailbox', { accountId: account.id, mailboxId: encodeUriFilter(mailbox.path) });
|
||||
}
|
||||
}
|
||||
|
||||
angular
|
||||
.module('SOGo.MailerUI')
|
||||
.controller('MailboxesController', MailboxesController);
|
||||
})();
|
||||
|
|
@ -34,7 +34,7 @@
|
|||
* @desc The factory we'll use to register with Angular
|
||||
* @returns the Message constructor
|
||||
*/
|
||||
Message.$factory = ['$q', '$timeout', '$log', '$sce', 'sgSettings', 'sgResource', function($q, $timeout, $log, $sce, Settings, Resource) {
|
||||
Message.$factory = ['$q', '$timeout', '$log', '$sce', 'sgSettings', 'Resource', function($q, $timeout, $log, $sce, Settings, Resource) {
|
||||
angular.extend(Message, {
|
||||
$q: $q,
|
||||
$timeout: $timeout,
|
||||
|
@ -52,7 +52,7 @@
|
|||
|
||||
/* Factory registration in Angular module */
|
||||
angular.module('SOGo.MailerUI')
|
||||
.factory('sgMessage', Message.$factory);
|
||||
.factory('Message', Message.$factory);
|
||||
|
||||
/**
|
||||
* @function filterTags
|
|
@ -0,0 +1,40 @@
|
|||
/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* @ngInject
|
||||
*/
|
||||
MessageController.$inject = ['$scope', '$rootScope', '$stateParams', '$state', 'stateAccount', 'stateMailbox', 'stateMessage', '$timeout', 'encodeUriFilter', 'sgFocus', 'Dialog', 'Account', 'Mailbox'];
|
||||
function MessageController($scope, $rootScope, $stateParams, $state, stateAccount, stateMailbox, stateMessage, $timeout, encodeUriFilter, focus, Dialog, Account, Mailbox) {
|
||||
$rootScope.message = stateMessage;
|
||||
$scope.tags = {};
|
||||
$scope.addOrRemoveTag = function(operation, tag) {
|
||||
if (tag) {
|
||||
stateMessage.$addOrRemoveTag(operation, tag);
|
||||
}
|
||||
};
|
||||
$scope.markAsFlaggedOrUnflagged = function() {
|
||||
var operation = (stateMessage.isflagged ? 'remove' : 'add');
|
||||
stateMessage.$markAsFlaggedOrUnflagged(operation).then(function() {
|
||||
stateMessage.isflagged = !stateMessage.isflagged;
|
||||
});
|
||||
};
|
||||
$scope.doDelete = function() {
|
||||
stateMailbox.$deleteMessages([stateMessage.uid]).then(function() {
|
||||
// Remove card from list of addressbook
|
||||
stateMailbox.$messages = _.reject(stateMailbox.$messages, function(o) {
|
||||
return o.uid == stateMessage.uid;
|
||||
});
|
||||
// Remove card object from scope
|
||||
$rootScope.message = null;
|
||||
$state.go('mail.account.mailbox', { accountId: stateAccount.id, mailboxId: encodeUriFilter(stateMailbox.path) });
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
angular
|
||||
.module('SOGo.MailerUI')
|
||||
.controller('MessageController', MessageController);
|
||||
})();
|
|
@ -0,0 +1,87 @@
|
|||
/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* @ngInject
|
||||
*/
|
||||
MessageEditorController.$inject = ['$scope', '$rootScope', '$stateParams', '$state', '$q', 'FileUploader', 'stateAccounts', 'stateMessage', '$timeout', 'encodeUriFilter', 'sgFocus', 'Dialog', 'Account', 'Mailbox', 'AddressBook'];
|
||||
function MessageEditorController($scope, $rootScope, $stateParams, $state, $q, FileUploader, stateAccounts, stateMessage, $timeout, encodeUriFilter, focus, Dialog, Account, Mailbox, AddressBook) {
|
||||
$scope.autocomplete = {to: {}, cc: {}, bcc: {}};
|
||||
$scope.hideCc = true;
|
||||
$scope.hideBcc = true;
|
||||
$scope.hideAttachments = true;
|
||||
if ($stateParams.actionName == 'reply') {
|
||||
stateMessage.$reply().then(function(msgObject) {
|
||||
console.debug("foo");
|
||||
|
||||
$scope.message = msgObject;
|
||||
$scope.hideCc = (!msgObject.editable.cc || msgObject.editable.cc.length == 0);
|
||||
$scope.hideBcc = (!msgObject.editable.bcc || msgObject.editable.bcc.length == 0);
|
||||
$scope.hideAttachments = true;
|
||||
});
|
||||
}
|
||||
else if ($stateParams.actionName == 'replyall') {
|
||||
stateMessage.$replyAll().then(function(msgObject) {
|
||||
$scope.message = msgObject;
|
||||
$scope.hideCc = (!msgObject.editable.cc || msgObject.editable.cc.length == 0);
|
||||
$scope.hideBcc = (!msgObject.editable.bcc || msgObject.editable.bcc.length == 0);
|
||||
$scope.hideAttachments = true;
|
||||
});
|
||||
}
|
||||
else if ($stateParams.actionName == 'forward') {
|
||||
stateMessage.$forward().then(function(msgObject) {
|
||||
$scope.message = msgObject;
|
||||
$scope.hideCc = true;
|
||||
$scope.hideBcc = true;
|
||||
$scope.hideAttachments = (!msgObject.editable.attachmentAttrs || msgObject.editable.attachmentAttrs.length == 0);
|
||||
});
|
||||
}
|
||||
else if (angular.isDefined(stateMessage)) {
|
||||
$scope.message = stateMessage;
|
||||
}
|
||||
$scope.identities = _.pluck(_.flatten(_.pluck(stateAccounts, 'identities')), 'full');
|
||||
$scope.cancel = function() {
|
||||
if ($scope.mailbox)
|
||||
$state.go('mail.account.mailbox', { accountId: $scope.mailbox.$account.id, mailboxId: encodeUriFilter($scope.mailbox.path) });
|
||||
else
|
||||
$state.go('mail');
|
||||
};
|
||||
$scope.send = function(message) {
|
||||
message.$send().then(function(data) {
|
||||
$rootScope.message = null;
|
||||
$state.go('mail');
|
||||
}, function(data) {
|
||||
console.debug('failure ' + JSON.stringify(data, undefined, 2));
|
||||
});
|
||||
};
|
||||
$scope.userFilter = function($query) {
|
||||
var deferred = $q.defer();
|
||||
AddressBook.$filterAll($query).then(function(results) {
|
||||
deferred.resolve(_.invoke(results, '$shortFormat', $query));
|
||||
});
|
||||
return deferred.promise;
|
||||
};
|
||||
$scope.uploader = new FileUploader({
|
||||
url: stateMessage.$absolutePath({asDraft: true}) + '/save',
|
||||
autoUpload: true,
|
||||
alias: 'attachments',
|
||||
onProgressItem: function(item, progress) {
|
||||
console.debug(item); console.debug(progress);
|
||||
},
|
||||
onSuccessItem: function(item, response, status, headers) {
|
||||
stateMessage.$setUID(response.uid);
|
||||
stateMessage.$reload();
|
||||
console.debug(item); console.debug('success = ' + JSON.stringify(response, undefined, 2));
|
||||
},
|
||||
onErrorItem: function(item, response, status, headers) {
|
||||
console.debug(item); console.debug('error = ' + JSON.stringify(response, undefined, 2));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
angular
|
||||
.module('SOGo.MailerUI')
|
||||
.controller('MessageEditorController', MessageEditorController);
|
||||
})();
|
|
@ -1,342 +0,0 @@
|
|||
/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* JavaScript for SOGo.MailerUI module */
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
angular.module('SOGo.Common', []);
|
||||
angular.module('SOGo.ContactsUI', []);
|
||||
|
||||
angular.module('SOGo.MailerUI', ['ngSanitize', 'ui.router', 'vs-repeat', 'ck', 'angularFileUpload', 'SOGo.Common', 'SOGo.UI', 'SOGo.UIDesktop', 'SOGo.ContactsUI', 'ngAnimate'])
|
||||
|
||||
.constant('sgSettings', {
|
||||
baseURL: ApplicationBaseURL,
|
||||
activeUser: {
|
||||
login: UserLogin,
|
||||
identification: UserIdentification,
|
||||
language: UserLanguage,
|
||||
folderURL: UserFolderURL,
|
||||
isSuperUser: IsSuperUser
|
||||
}
|
||||
})
|
||||
|
||||
.config(['$stateProvider', '$urlRouterProvider', function($stateProvider, $urlRouterProvider) {
|
||||
$stateProvider
|
||||
.state('mail', {
|
||||
url: '/Mail',
|
||||
views: {
|
||||
mailboxes: {
|
||||
templateUrl: 'UIxMailMainFrame', // UI/Templates/MailerUI/UIxMailMainFrame.wox
|
||||
controller: 'MailboxesCtrl'
|
||||
}
|
||||
},
|
||||
resolve: {
|
||||
stateAccounts: ['$q', 'sgAccount', function($q, Account) {
|
||||
var accounts = Account.$findAll(mailAccounts);
|
||||
var promises = [];
|
||||
// Fetch list of mailboxes for each account
|
||||
angular.forEach(accounts, function(account, i) {
|
||||
var mailboxes = account.$getMailboxes();
|
||||
promises.push(mailboxes.then(function(objects) {
|
||||
return account;
|
||||
}));
|
||||
});
|
||||
return $q.all(promises);
|
||||
}]
|
||||
}
|
||||
})
|
||||
.state('mail.account', {
|
||||
url: '/:accountId',
|
||||
abstract: true,
|
||||
views: {
|
||||
mailbox: {
|
||||
template: '<ui-view/>',
|
||||
}
|
||||
},
|
||||
resolve: {
|
||||
stateAccount: ['$stateParams', 'stateAccounts', function($stateParams, stateAccounts) {
|
||||
return _.find(stateAccounts, function(account) {
|
||||
return account.id == $stateParams.accountId;
|
||||
});
|
||||
}]
|
||||
}
|
||||
})
|
||||
.state('mail.account.mailbox', {
|
||||
url: '/:mailboxId',
|
||||
views: {
|
||||
'mailbox@mail': {
|
||||
templateUrl: 'UIxMailFolderTemplate', // UI/Templates/MailerUI/UIxMailFolderTemplate.wox
|
||||
controller: 'MailboxCtrl'
|
||||
}
|
||||
},
|
||||
resolve: {
|
||||
stateMailbox: ['$stateParams', 'stateAccount', 'decodeUriFilter', function($stateParams, stateAccount, decodeUriFilter) {
|
||||
var mailboxId = decodeUriFilter($stateParams.mailboxId);
|
||||
// Recursive find function
|
||||
var _find = function(mailboxes) {
|
||||
var mailbox = _.find(mailboxes, function(o) {
|
||||
return o.path == mailboxId;
|
||||
});
|
||||
if (!mailbox) {
|
||||
angular.forEach(mailboxes, function(o) {
|
||||
if (!mailbox && o.children && o.children.length > 0) {
|
||||
mailbox = _find(o.children);
|
||||
}
|
||||
});
|
||||
}
|
||||
return mailbox;
|
||||
};
|
||||
return _find(stateAccount.$mailboxes);
|
||||
}],
|
||||
stateMessages: ['stateMailbox', function(stateMailbox) {
|
||||
return stateMailbox.$filter();
|
||||
}]
|
||||
}
|
||||
})
|
||||
.state('mail.account.mailbox.message', {
|
||||
url: '/:messageId',
|
||||
views: {
|
||||
message: {
|
||||
templateUrl: 'UIxMailViewTemplate', // UI/Templates/MailerUI/UIxMailViewTemplate.wox
|
||||
controller: 'MessageCtrl'
|
||||
}
|
||||
},
|
||||
resolve: {
|
||||
stateMessage: ['encodeUriFilter', '$stateParams', '$state', 'stateMailbox', 'stateMessages', function(encodeUriFilter, $stateParams, $state, stateMailbox, stateMessages) {
|
||||
var message = _.find(stateMessages, function(messageObject) {
|
||||
return messageObject.uid == $stateParams.messageId;
|
||||
});
|
||||
|
||||
if (message)
|
||||
return message.$reload();
|
||||
else
|
||||
// Message not found
|
||||
$state.go('mail.account.mailbox', { accountId: stateMailbox.$account.id, mailboxId: encodeUriFilter(stateMailbox.path) });
|
||||
}]
|
||||
}
|
||||
})
|
||||
.state('mail.account.mailbox.message.edit', {
|
||||
url: '/edit',
|
||||
views: {
|
||||
'mailbox@mail': {
|
||||
templateUrl: 'UIxMailEditor', // UI/Templates/MailerUI/UIxMailEditor.wox
|
||||
controller: 'MessageEditorCtrl'
|
||||
}
|
||||
},
|
||||
resolve: {
|
||||
stateContent: ['stateMessage', function(stateMessage) {
|
||||
return stateMessage.$editableContent();
|
||||
}]
|
||||
}
|
||||
})
|
||||
.state('mail.account.mailbox.message.action', {
|
||||
url: '/{actionName:(?:reply|replyall|forward)}',
|
||||
views: {
|
||||
'mailbox@mail': {
|
||||
templateUrl: 'UIxMailEditor', // UI/Templates/MailerUI/UIxMailEditor.wox
|
||||
controller: 'MessageEditorCtrl'
|
||||
}
|
||||
}
|
||||
})
|
||||
.state('mail.newMessage', {
|
||||
url: '/new',
|
||||
views: {
|
||||
mailbox: {
|
||||
templateUrl: 'UIxMailEditor', // UI/Templates/MailerUI/UIxMailEditor.wox
|
||||
controller: 'MessageEditorCtrl'
|
||||
}
|
||||
},
|
||||
resolve: {
|
||||
stateMessage: ['stateAccounts', function(stateAccounts) {
|
||||
if (stateAccounts.length > 0) {
|
||||
return stateAccounts[0].$newMessage();
|
||||
}
|
||||
}]
|
||||
}
|
||||
});
|
||||
|
||||
// if none of the above states are matched, use this as the fallback
|
||||
$urlRouterProvider.otherwise('/Mail');
|
||||
|
||||
// Set default configuration for tags input
|
||||
// tagsInputConfigProvider.setDefaults('tagsInput', {
|
||||
// addOnComma: false,
|
||||
// replaceSpacesWithDashes: false,
|
||||
// allowedTagsPattern: /([\w\!\#$\%\&\'\*\+\-\/\=\?\^\`{\|\}\~]+\.)*[\w\!\#$\%\&\'\*\+\-\/\=\?\^\`{\|\}\~]+@((((([a-z0-9]{1}[a-z0-9\-]{0,62}[a-z0-9]{1})|[a-z])\.)+[a-z]{2,})|(\d{1,3}\.){3}\d{1,3}(\:\d{1,5})?)/i
|
||||
// });
|
||||
}])
|
||||
|
||||
.run(function($rootScope) {
|
||||
$rootScope.$on('$routeChangeError', function(event, current, previous, rejection) {
|
||||
console.error(event, current, previous, rejection)
|
||||
})
|
||||
})
|
||||
|
||||
.controller('MailboxesCtrl', ['$scope', '$rootScope', '$stateParams', '$state', '$timeout', 'sgFocus', 'encodeUriFilter', 'sgDialog', 'sgSettings', 'sgAccount', 'sgMailbox', 'stateAccounts', function($scope, $rootScope, $stateParams, $state, $timeout, focus, encodeUriFilter, Dialog, Settings, Account, Mailbox, stateAccounts) {
|
||||
$scope.activeUser = Settings.activeUser;
|
||||
$scope.accounts = stateAccounts;
|
||||
|
||||
$scope.newFolder = function(parentFolder) {
|
||||
Dialog.prompt(l('New folder'),
|
||||
l('Enter the new name of your folder :'))
|
||||
.then(function(name) {
|
||||
parentFolder.$newMailbox(parentFolder.id, name);
|
||||
});
|
||||
};
|
||||
$scope.editFolder = function(folder) {
|
||||
$scope.editMode = folder.path;
|
||||
focus('mailboxName_' + folder.path);
|
||||
};
|
||||
$scope.revertEditing = function(folder) {
|
||||
folder.$reset();
|
||||
$scope.editMode = false;
|
||||
};
|
||||
$scope.selectFolder = function(account, folder) {
|
||||
if ($scope.editMode == folder.path)
|
||||
return;
|
||||
$rootScope.currentFolder = folder;
|
||||
$scope.editMode = false;
|
||||
$rootScope.message = null;
|
||||
$state.go('mail.account.mailbox', { accountId: account.id, mailboxId: encodeUriFilter(folder.path) });
|
||||
};
|
||||
$scope.saveFolder = function(folder) {
|
||||
folder.$rename();
|
||||
};
|
||||
$scope.exportMails = function() {
|
||||
window.location.href = ApplicationBaseURL + '/' + $rootScope.currentFolder.id + '/exportFolder';
|
||||
};
|
||||
$scope.confirmDelete = function(folder) {
|
||||
if (folder.path != $scope.currentFolder.path) {
|
||||
// Counter the possibility to click on the "hidden" secondary button
|
||||
$scope.selectFolder(folder.$account, folder);
|
||||
return;
|
||||
}
|
||||
Dialog.confirm(l('Confirmation'), l('Do you really want to move this folder into the trash ?'))
|
||||
.then(function() {
|
||||
folder.$delete()
|
||||
.then(function() {
|
||||
$rootScope.currentFolder = null;
|
||||
$state.go('mail');
|
||||
}, function(data, status) {
|
||||
Dialog.alert(l('An error occured while deleting the mailbox "%{0}".', folder.name),
|
||||
l(data.error));
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
if ($state.current.name == 'mail' && $scope.accounts.length > 0 && $scope.accounts[0].$mailboxes.length > 0) {
|
||||
// Redirect to first mailbox of first account if no mailbox is selected
|
||||
var account = $scope.accounts[0];
|
||||
var mailbox = account.$mailboxes[0];
|
||||
$state.go('mail.account.mailbox', { accountId: account.id, mailboxId: encodeUriFilter(mailbox.path) });
|
||||
}
|
||||
}])
|
||||
|
||||
.controller('MailboxCtrl', ['$scope', '$rootScope', '$stateParams', 'stateAccount', 'stateMailbox', '$timeout', 'sgFocus', 'sgDialog', 'sgAccount', 'sgMailbox', function($scope, $rootScope, $stateParams, stateAccount, stateMailbox, $timeout, focus, Dialog, Account, Mailbox) {
|
||||
$scope.account = stateAccount;
|
||||
$rootScope.mailbox = stateMailbox;
|
||||
$rootScope.currentFolder = stateMailbox;
|
||||
}])
|
||||
|
||||
.controller('MessageCtrl', ['$scope', '$rootScope', '$stateParams', '$state', 'stateAccount', 'stateMailbox', 'stateMessage', '$timeout', 'encodeUriFilter', 'sgFocus', 'sgDialog', 'sgAccount', 'sgMailbox', function($scope, $rootScope, $stateParams, $state, stateAccount, stateMailbox, stateMessage, $timeout, encodeUriFilter, focus, Dialog, Account, Mailbox) {
|
||||
$rootScope.message = stateMessage;
|
||||
$scope.tags = {};
|
||||
$scope.addOrRemoveTag = function(operation, tag) {
|
||||
if (tag) {
|
||||
stateMessage.$addOrRemoveTag(operation, tag);
|
||||
}
|
||||
};
|
||||
$scope.markAsFlaggedOrUnflagged = function() {
|
||||
var operation = (stateMessage.isflagged ? 'remove' : 'add');
|
||||
stateMessage.$markAsFlaggedOrUnflagged(operation).then(function() {
|
||||
stateMessage.isflagged = !stateMessage.isflagged;
|
||||
});
|
||||
};
|
||||
$scope.doDelete = function() {
|
||||
stateMailbox.$deleteMessages([stateMessage.uid]).then(function() {
|
||||
// Remove card from list of addressbook
|
||||
stateMailbox.$messages = _.reject(stateMailbox.$messages, function(o) {
|
||||
return o.uid == stateMessage.uid;
|
||||
});
|
||||
// Remove card object from scope
|
||||
$rootScope.message = null;
|
||||
$state.go('mail.account.mailbox', { accountId: stateAccount.id, mailboxId: encodeUriFilter(stateMailbox.path) });
|
||||
});
|
||||
};
|
||||
}])
|
||||
|
||||
.controller('MessageEditorCtrl', ['$scope', '$rootScope', '$stateParams', '$state', '$q', 'FileUploader', 'stateAccounts', 'stateMessage', '$timeout', 'encodeUriFilter', 'sgFocus', 'sgDialog', 'sgAccount', 'sgMailbox', 'sgAddressBook', function($scope, $rootScope, $stateParams, $state, $q, FileUploader, stateAccounts, stateMessage, $timeout, encodeUriFilter, focus, Dialog, Account, Mailbox, AddressBook) {
|
||||
$scope.autocomplete = {to: {}, cc: {}, bcc: {}};
|
||||
$scope.hideCc = true;
|
||||
$scope.hideBcc = true;
|
||||
$scope.hideAttachments = true;
|
||||
if ($stateParams.actionName == 'reply') {
|
||||
stateMessage.$reply().then(function(msgObject) {
|
||||
console.debug("foo");
|
||||
|
||||
$scope.message = msgObject;
|
||||
$scope.hideCc = (!msgObject.editable.cc || msgObject.editable.cc.length == 0);
|
||||
$scope.hideBcc = (!msgObject.editable.bcc || msgObject.editable.bcc.length == 0);
|
||||
$scope.hideAttachments = true;
|
||||
});
|
||||
}
|
||||
else if ($stateParams.actionName == 'replyall') {
|
||||
stateMessage.$replyAll().then(function(msgObject) {
|
||||
$scope.message = msgObject;
|
||||
$scope.hideCc = (!msgObject.editable.cc || msgObject.editable.cc.length == 0);
|
||||
$scope.hideBcc = (!msgObject.editable.bcc || msgObject.editable.bcc.length == 0);
|
||||
$scope.hideAttachments = true;
|
||||
});
|
||||
}
|
||||
else if ($stateParams.actionName == 'forward') {
|
||||
stateMessage.$forward().then(function(msgObject) {
|
||||
$scope.message = msgObject;
|
||||
$scope.hideCc = true;
|
||||
$scope.hideBcc = true;
|
||||
$scope.hideAttachments = (!msgObject.editable.attachmentAttrs || msgObject.editable.attachmentAttrs.length == 0);
|
||||
});
|
||||
}
|
||||
else if (angular.isDefined(stateMessage)) {
|
||||
$scope.message = stateMessage;
|
||||
}
|
||||
$scope.identities = _.pluck(_.flatten(_.pluck(stateAccounts, 'identities')), 'full');
|
||||
$scope.cancel = function() {
|
||||
if ($scope.mailbox)
|
||||
$state.go('mail.account.mailbox', { accountId: $scope.mailbox.$account.id, mailboxId: encodeUriFilter($scope.mailbox.path) });
|
||||
else
|
||||
$state.go('mail');
|
||||
};
|
||||
$scope.send = function(message) {
|
||||
message.$send().then(function(data) {
|
||||
$rootScope.message = null;
|
||||
$state.go('mail');
|
||||
}, function(data) {
|
||||
console.debug('failure ' + JSON.stringify(data, undefined, 2));
|
||||
});
|
||||
};
|
||||
$scope.userFilter = function($query) {
|
||||
var deferred = $q.defer();
|
||||
AddressBook.$filterAll($query).then(function(results) {
|
||||
deferred.resolve(_.invoke(results, '$shortFormat', $query));
|
||||
});
|
||||
return deferred.promise;
|
||||
};
|
||||
$scope.uploader = new FileUploader({
|
||||
url: stateMessage.$absolutePath({asDraft: true}) + '/save',
|
||||
autoUpload: true,
|
||||
alias: 'attachments',
|
||||
onProgressItem: function(item, progress) {
|
||||
console.debug(item); console.debug(progress);
|
||||
},
|
||||
onSuccessItem: function(item, response, status, headers) {
|
||||
stateMessage.$setUID(response.uid);
|
||||
stateMessage.$reload();
|
||||
console.debug(item); console.debug('success = ' + JSON.stringify(response, undefined, 2));
|
||||
},
|
||||
onErrorItem: function(item, response, status, headers) {
|
||||
console.debug(item); console.debug('error = ' + JSON.stringify(response, undefined, 2));
|
||||
}
|
||||
});
|
||||
}]);
|
||||
|
||||
})();
|
|
@ -0,0 +1,88 @@
|
|||
/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* JavaScript for SOGoPreferences */
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
angular.module('SOGo.ContactsUI', []);
|
||||
angular.module('SOGo.MailerUI', []);
|
||||
|
||||
angular.module('SOGo.PreferencesUI', ['ngSanitize', 'ui.router', 'SOGo.Common', 'SOGo.MailerUI', 'SOGo.ContactsUI', 'SOGo.Authentication'])
|
||||
|
||||
.constant('sgSettings', {
|
||||
baseURL: ApplicationBaseURL,
|
||||
activeUser: {
|
||||
login: UserLogin,
|
||||
identification: UserIdentification,
|
||||
language: UserLanguage,
|
||||
folderURL: UserFolderURL,
|
||||
isSuperUser: IsSuperUser
|
||||
}
|
||||
})
|
||||
.config(configure);
|
||||
|
||||
/**
|
||||
* @ngInject
|
||||
*/
|
||||
configure.$inject = ['$stateProvider', '$urlRouterProvider'];
|
||||
function configure($stateProvider, $urlRouterProvider) {
|
||||
$stateProvider
|
||||
.state('preferences', {
|
||||
abstract: true,
|
||||
views: {
|
||||
preferences: {
|
||||
templateUrl: 'preferences.html',
|
||||
controller: 'PreferencesController',
|
||||
controllerAs: 'app'
|
||||
}
|
||||
},
|
||||
resolve: {
|
||||
statePreferences: statePreferences
|
||||
}
|
||||
})
|
||||
.state('preferences.general', {
|
||||
url: '/general',
|
||||
views: {
|
||||
module: {
|
||||
templateUrl: 'generalPreferences.html'
|
||||
}
|
||||
}
|
||||
})
|
||||
.state('preferences.calendars', {
|
||||
url: '/calendars',
|
||||
views: {
|
||||
module: {
|
||||
templateUrl: 'calendarsPreferences.html'
|
||||
}
|
||||
}
|
||||
})
|
||||
.state('preferences.addressbooks', {
|
||||
url: '/addressbooks',
|
||||
views: {
|
||||
module: {
|
||||
templateUrl: 'addressbooksPreferences.html'
|
||||
}
|
||||
}
|
||||
})
|
||||
.state('preferences.mailer', {
|
||||
url: '/mailer',
|
||||
views: {
|
||||
module: {
|
||||
templateUrl: 'mailerPreferences.html'
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// if none of the above states are matched, use this as the fallback
|
||||
$urlRouterProvider.otherwise('/general');
|
||||
}
|
||||
|
||||
/**
|
||||
* @ngInject
|
||||
*/
|
||||
statePreferences.$inject = ['Preferences'];
|
||||
function statePreferences(Preferences) {
|
||||
return new Preferences();
|
||||
}
|
||||
|
||||
})();
|
|
@ -0,0 +1,32 @@
|
|||
/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* JavaScript for SOGoPreferences */
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* @ngInject
|
||||
*/
|
||||
AccountDialogController.$inject = ['$scope', '$mdDialog', 'account', 'accountId', 'mailCustomFromEnabled'];
|
||||
function AccountDialogController($scope, $mdDialog, account, accountId, mailCustomFromEnabled) {
|
||||
$scope.account = account;
|
||||
$scope.accountId = accountId;
|
||||
$scope.customFromIsReadonly = function() {
|
||||
if (accountId > 0)
|
||||
return false;
|
||||
|
||||
return !mailCustomFromEnabled;
|
||||
};
|
||||
$scope.cancel = function() {
|
||||
$mdDialog.cancel();
|
||||
};
|
||||
$scope.save = function() {
|
||||
$mdDialog.hide();
|
||||
};
|
||||
}
|
||||
|
||||
angular
|
||||
.module('SOGo.PreferencesUI')
|
||||
.controller('AccountDialogController', AccountDialogController);
|
||||
|
||||
})();
|
|
@ -0,0 +1,98 @@
|
|||
/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* JavaScript for SOGoPreferences */
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* @ngInject
|
||||
*/
|
||||
FiltersDialogController.$inject = ['$scope', '$mdDialog', 'filter', 'mailboxes', 'labels'];
|
||||
function FiltersDialogController($scope, $mdDialog, filter, mailboxes, labels) {
|
||||
$scope.filter = filter;
|
||||
$scope.mailboxes = mailboxes;
|
||||
$scope.labels = labels;
|
||||
|
||||
$scope.fieldLabels = {
|
||||
"subject": l("Subject"),
|
||||
"from": l("From"),
|
||||
"to": l("To"),
|
||||
"cc": l("Cc"),
|
||||
"to_or_cc": l("To or Cc"),
|
||||
"size": l("Size (Kb)"),
|
||||
"header": l("Header"),
|
||||
"body": l("Body")
|
||||
};
|
||||
|
||||
$scope.methodLabels = {
|
||||
"addflag": l("Flag the message with:"),
|
||||
"discard": l("Discard the message"),
|
||||
"fileinto": l("File the message in:"),
|
||||
"keep": l("Keep the message"),
|
||||
"redirect": l("Forward the message to:"),
|
||||
"reject": l("Send a reject message:"),
|
||||
"vacation": l("Send a vacation message"),
|
||||
"stop": l("Stop processing filter rules")
|
||||
};
|
||||
|
||||
$scope.numberOperatorLabels = {
|
||||
"under": l("is under"),
|
||||
"over": l("is over")
|
||||
};
|
||||
|
||||
$scope.textOperatorLabels = {
|
||||
"is": l("is"),
|
||||
"is_not": l("is not"),
|
||||
"contains": l("contains"),
|
||||
"contains_not": l("does not contain"),
|
||||
"matches": l("matches"),
|
||||
"matches_not": l("does not match"),
|
||||
"regex": l("matches regex"),
|
||||
"regex_not": l("does not match regex")
|
||||
};
|
||||
|
||||
$scope.flagLabels = {
|
||||
"seen": l("Seen"),
|
||||
"deleted": l("Deleted"),
|
||||
"answered": l("Answered"),
|
||||
"flagged": l("Flagged"),
|
||||
"junk": l("Junk"),
|
||||
"not_junk": l("Not Junk")
|
||||
};
|
||||
|
||||
$scope.cancel = function() {
|
||||
$mdDialog.cancel();
|
||||
};
|
||||
|
||||
$scope.save = function() {
|
||||
$mdDialog.hide();
|
||||
};
|
||||
|
||||
$scope.addMailFilterRule = function(event) {
|
||||
if (!$scope.filter.rules)
|
||||
$scope.filter.rules = [];
|
||||
|
||||
$scope.filter.rules.push({});
|
||||
};
|
||||
|
||||
$scope.removeMailFilterRule = function(index) {
|
||||
$scope.filter.rules.splice(index, 1);
|
||||
};
|
||||
|
||||
$scope.addMailFilterAction = function(event) {
|
||||
if (!$scope.filter.actions)
|
||||
$scope.filter.actions = [];
|
||||
|
||||
$scope.filter.actions.push({});
|
||||
};
|
||||
|
||||
$scope.removeMailFilterAction = function(index) {
|
||||
$scope.filter.actions.splice(index, 1);
|
||||
};
|
||||
}
|
||||
|
||||
angular
|
||||
.module('SOGo.PreferencesUI')
|
||||
.controller('FiltersDialogController', FiltersDialogController);
|
||||
|
||||
})();
|
|
@ -13,45 +13,45 @@
|
|||
this.defaults = {};
|
||||
this.settings = {};
|
||||
|
||||
this.mailboxes = Preferences.$Mailbox.$find({ id: 0 });
|
||||
this.mailboxes = Preferences.$Mailbox.$find({ id: 0 });
|
||||
|
||||
Preferences.$$resource.fetch("jsonDefaults").then(function(data) {
|
||||
Preferences.$timeout(function() {
|
||||
Preferences.$$resource.fetch("jsonDefaults").then(function(data) {
|
||||
Preferences.$timeout(function() {
|
||||
|
||||
// We swap $key -> _$key to avoid an Angular bug (https://github.com/angular/angular.js/issues/6266)
|
||||
var labels = _.object(_.map(data.SOGoMailLabelsColors, function(value, key) {
|
||||
if (key.charAt(0) == '$')
|
||||
return ['_' + key, value];
|
||||
return [key, value];
|
||||
}));
|
||||
// We swap $key -> _$key to avoid an Angular bug (https://github.com/angular/angular.js/issues/6266)
|
||||
var labels = _.object(_.map(data.SOGoMailLabelsColors, function(value, key) {
|
||||
if (key.charAt(0) == '$')
|
||||
return ['_' + key, value];
|
||||
return [key, value];
|
||||
}));
|
||||
|
||||
data.SOGoMailLabelsColors = labels;
|
||||
data.SOGoMailLabelsColors = labels;
|
||||
|
||||
// We convert our list of autoReplyEmailAddresses/forwardAddress into a string.
|
||||
if (data.Vacation && data.Vacation.autoReplyEmailAddresses)
|
||||
data.Vacation.autoReplyEmailAddresses = data.Vacation.autoReplyEmailAddresses.join(",");
|
||||
// We convert our list of autoReplyEmailAddresses/forwardAddress into a string.
|
||||
if (data.Vacation && data.Vacation.autoReplyEmailAddresses)
|
||||
data.Vacation.autoReplyEmailAddresses = data.Vacation.autoReplyEmailAddresses.join(",");
|
||||
|
||||
if (data.Forward && data.Forward.forwardAddress)
|
||||
data.Forward.forwardAddress = data.Forward.forwardAddress.join(",");
|
||||
if (data.Forward && data.Forward.forwardAddress)
|
||||
data.Forward.forwardAddress = data.Forward.forwardAddress.join(",");
|
||||
|
||||
angular.extend(_this.defaults, data);
|
||||
});
|
||||
});
|
||||
Preferences.$$resource.fetch("jsonSettings").then(function(data) {
|
||||
Preferences.$timeout(function() {
|
||||
angular.extend(_this.defaults, data);
|
||||
});
|
||||
});
|
||||
Preferences.$$resource.fetch("jsonSettings").then(function(data) {
|
||||
Preferences.$timeout(function() {
|
||||
|
||||
|
||||
// We convert our PreventInvitationsWhitelist hash into a array of user
|
||||
if (data.Calendar && data.Calendar.PreventInvitationsWhitelist)
|
||||
data.Calendar.PreventInvitationsWhitelist = _.map(data.Calendar.PreventInvitationsWhitelist, function(value, key) {
|
||||
return new Preferences.$User({uid: key, shortFormat: value});
|
||||
});
|
||||
else
|
||||
data.Calendar.PreventInvitationsWhitelist = [];
|
||||
// We convert our PreventInvitationsWhitelist hash into a array of user
|
||||
if (data.Calendar && data.Calendar.PreventInvitationsWhitelist)
|
||||
data.Calendar.PreventInvitationsWhitelist = _.map(data.Calendar.PreventInvitationsWhitelist, function(value, key) {
|
||||
return new Preferences.$User({uid: key, shortFormat: value});
|
||||
});
|
||||
else
|
||||
data.Calendar.PreventInvitationsWhitelist = [];
|
||||
|
||||
angular.extend(_this.settings, data);
|
||||
});
|
||||
});
|
||||
angular.extend(_this.settings, data);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -59,7 +59,7 @@
|
|||
* @desc The factory we'll use to register with Angular
|
||||
* @returns the Preferences constructor
|
||||
*/
|
||||
Preferences.$factory = ['$q', '$timeout', '$log', 'sgSettings', 'sgResource', 'sgMailbox', 'sgUser', function($q, $timeout, $log, Settings, Resource, Mailbox, User) {
|
||||
Preferences.$factory = ['$q', '$timeout', '$log', 'sgSettings', 'Resource', 'Mailbox', 'User', function($q, $timeout, $log, Settings, Resource, Mailbox, User) {
|
||||
angular.extend(Preferences, {
|
||||
$q: $q,
|
||||
$timeout: $timeout,
|
||||
|
@ -75,14 +75,14 @@
|
|||
|
||||
/* Factory registration in Angular module */
|
||||
angular.module('SOGo.PreferencesUI')
|
||||
.factory('sgPreferences', Preferences.$factory);
|
||||
.factory('Preferences', Preferences.$factory);
|
||||
|
||||
/**
|
||||
* @function $save
|
||||
* @memberof Preferences.prototype
|
||||
* @desc Save the preferences to the server.
|
||||
*/
|
||||
Preferences.prototype.$save = function() {
|
||||
/*Preferences.prototype.$save = function() {
|
||||
var _this = this;
|
||||
console.debug("save in model...");
|
||||
|
||||
|
@ -94,7 +94,7 @@
|
|||
//_this.$shadowData = _this.$omit(true);
|
||||
return data;
|
||||
});
|
||||
};
|
||||
};*/
|
||||
|
||||
/**
|
||||
* @function $omit
|
||||
|
@ -103,7 +103,7 @@
|
|||
* @param {Boolean} [deep] - make a deep copy if true
|
||||
* @return an object literal copy of the Preferences instance
|
||||
*/
|
||||
Preferences.prototype.$omit = function(deep) {
|
||||
/*Preferences.prototype.$omit = function(deep) {
|
||||
var preferences = {};
|
||||
angular.forEach(this, function(value, key) {
|
||||
if (key != 'constructor' && key[0] != '$') {
|
||||
|
@ -139,6 +139,6 @@
|
|||
}
|
||||
|
||||
return preferences;
|
||||
};
|
||||
};*/
|
||||
|
||||
})();
|
|
@ -0,0 +1,198 @@
|
|||
/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* JavaScript for SOGoPreferences */
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* @ngInject
|
||||
*/
|
||||
PreferencesController.$inject = ['$scope', '$timeout', '$q', '$mdDialog', 'Preferences', 'User', 'statePreferences', 'Authentication'];
|
||||
function PreferencesController($scope, $timeout, $q, $mdDialog, Preferences, User, statePreferences, Authentication) {
|
||||
var vm = this;
|
||||
|
||||
vm.preferences = statePreferences;
|
||||
vm.passwords = { newPassword: null, newPasswordConfirmation: null };
|
||||
|
||||
vm.addCalendarCategory = addCalendarCategory;
|
||||
vm.removeCalendarCategory = removeCalendarCategory;
|
||||
vm.addContactCategory = addContactCategory;
|
||||
vm.removeContactCategory = removeContactCategory;
|
||||
vm.addMailAccount = addMailAccount;
|
||||
vm.editMailAccount = editMailAccount;
|
||||
vm.removeMailAccount = removeMailAccount;
|
||||
vm.addMailLabel = addMailLabel;
|
||||
vm.removeMailLabel = removeMailLabel;
|
||||
vm.addMailFilter = addMailFilter;
|
||||
vm.editMailFilter = editMailFilter;
|
||||
vm.removeMailFilter = removeMailFilter;
|
||||
vm.userFilter = userFilter;
|
||||
vm.save = save;
|
||||
vm.canChangePassword = canChangePassword;
|
||||
vm.changePassword = changePassword;
|
||||
|
||||
function addCalendarCategory() {
|
||||
vm.preferences.defaults.SOGoCalendarCategoriesColors["New category"] = "#aaa";
|
||||
vm.preferences.defaults.SOGoCalendarCategories.push("New category");
|
||||
}
|
||||
|
||||
function removeCalendarCategory(index) {
|
||||
var key = vm.preferences.defaults.SOGoCalendarCategories[index];
|
||||
vm.preferences.defaults.SOGoCalendarCategories.splice(index, 1);
|
||||
delete vm.preferences.defaults.SOGoCalendarCategoriesColors[key];
|
||||
}
|
||||
|
||||
function addContactCategory() {
|
||||
vm.preferences.defaults.SOGoContactsCategories.push("");
|
||||
}
|
||||
|
||||
function removeContactCategory(index) {
|
||||
vm.preferences.defaults.SOGoContactsCategories.splice(index, 1);
|
||||
}
|
||||
|
||||
function addMailAccount(ev) {
|
||||
var account;
|
||||
|
||||
vm.preferences.defaults.AuxiliaryMailAccounts.push({});
|
||||
account = _.last(vm.preferences.defaults.AuxiliaryMailAccounts);
|
||||
account['name'] = "New account";
|
||||
account['identities'] = [];
|
||||
account['identities'][0] = {};
|
||||
account['identities'][0]['fullName'] = "";
|
||||
account['identities'][0]['email'] = "";
|
||||
account['receipts'] = {};
|
||||
account['receipts']['receiptAction'] = "ignore";
|
||||
account['receipts']['receiptNonRecipientAction'] = "ignore";
|
||||
account['receipts']['receiptOutsideDomainAction'] = "ignore";
|
||||
account['receipts']['receiptAnyAction'] = "ignore";
|
||||
|
||||
$mdDialog.show({
|
||||
controller: 'AccountDialogController',
|
||||
templateUrl: 'editAccount?account=new',
|
||||
targetEvent: ev,
|
||||
locals: {
|
||||
account: account,
|
||||
accountId: (vm.preferences.defaults.AuxiliaryMailAccounts.length-1),
|
||||
mailCustomFromEnabled: window.mailCustomFromEnabled
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function editMailAccount(index) {
|
||||
var account = vm.preferences.defaults.AuxiliaryMailAccounts[index];
|
||||
$mdDialog.show({
|
||||
controller: 'AccountDialogController',
|
||||
templateUrl: 'editAccount?account=' + index,
|
||||
targetEvent: null,
|
||||
locals: {
|
||||
account: account,
|
||||
accountId: index,
|
||||
mailCustomFromEnabled: window.mailCustomFromEnabled
|
||||
}
|
||||
}).then(function() {
|
||||
vm.preferences.defaults.AuxiliaryMailAccounts[index] = account;
|
||||
});
|
||||
}
|
||||
|
||||
function removeMailAccount(index) {
|
||||
vm.preferences.defaults.AuxiliaryMailAccounts.splice(index, 1);
|
||||
}
|
||||
|
||||
function addMailLabel() {
|
||||
vm.preferences.defaults.SOGoMailLabelsColors["new_label"] = ["New label", "#aaa"];
|
||||
}
|
||||
|
||||
function removeMailLabel(key) {
|
||||
delete vm.preferences.defaults.SOGoMailLabelsColors[key];
|
||||
}
|
||||
|
||||
function addMailFilter(ev) {
|
||||
if (!vm.preferences.defaults.SOGoSieveFilters)
|
||||
vm.preferences.defaults.SOGoSieveFilters = [];
|
||||
|
||||
vm.preferences.defaults.SOGoSieveFilters.push({});
|
||||
var filter = _.last(vm.preferences.defaults.SOGoSieveFilters);
|
||||
$mdDialog.show({
|
||||
controller: 'FiltersDialogController',
|
||||
templateUrl: 'editFilter?filter=new',
|
||||
targetEvent: ev,
|
||||
locals: {
|
||||
filter: filter,
|
||||
mailboxes: vm.preferences.mailboxes,
|
||||
labels: vm.preferences.defaults.SOGoMailLabelsColors
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function editMailFilter(index) {
|
||||
var filter = angular.copy(vm.preferences.defaults.SOGoSieveFilters[index]);
|
||||
|
||||
$mdDialog.show({
|
||||
controller: 'FiltersDialogController',
|
||||
templateUrl: 'editFilter?filter=' + index,
|
||||
targetEvent: null,
|
||||
locals: {
|
||||
filter: filter,
|
||||
mailboxes: vm.preferences.mailboxes,
|
||||
labels: vm.preferences.defaults.SOGoMailLabelsColors
|
||||
}
|
||||
}).then(function() {
|
||||
vm.preferences.defaults.SOGoSieveFilters[index] = filter;
|
||||
});
|
||||
}
|
||||
|
||||
function removeMailFilter(index) {
|
||||
vm.preferences.defaults.SOGoSieveFilters.splice(index, 1);
|
||||
}
|
||||
|
||||
function userFilter($query) {
|
||||
var deferred = $q.defer();
|
||||
User.$filter($query).then(function(results) {
|
||||
deferred.resolve(results)
|
||||
});
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function save() {
|
||||
vm.preferences.$save();
|
||||
}
|
||||
|
||||
function canChangePassword() {
|
||||
if (vm.passwords.newPassword && vm.passwords.newPassword.length > 0 &&
|
||||
vm.passwords.newPasswordConfirmation && vm.passwords.newPasswordConfirmation.length &&
|
||||
vm.passwords.newPassword == vm.passwords.newPasswordConfirmation)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function changePassword() {
|
||||
Authentication.changePassword(vm.passwords.newPassword).then(function() {
|
||||
var alert = $mdDialog.alert({
|
||||
title: l('Password'),
|
||||
content: l('The password was changed successfully.'),
|
||||
ok: 'OK'
|
||||
});
|
||||
$mdDialog.show( alert )
|
||||
.finally(function() {
|
||||
alert = undefined;
|
||||
});
|
||||
}, function(msg) {
|
||||
var alert = $mdDialog.alert({
|
||||
title: l('Password'),
|
||||
content: msg,
|
||||
ok: 'OK'
|
||||
});
|
||||
$mdDialog.show( alert )
|
||||
.finally(function() {
|
||||
alert = undefined;
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
angular
|
||||
.module('SOGo.PreferencesUI')
|
||||
.controller('PreferencesController', PreferencesController);
|
||||
|
||||
})();
|
|
@ -1,317 +0,0 @@
|
|||
/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* JavaScript for SOGoPreferences */
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
angular.module('SOGo.Common', []);
|
||||
angular.module('SOGo.ContactsUI', []);
|
||||
angular.module('SOGo.MailerUI', []);
|
||||
|
||||
angular.module('SOGo.PreferencesUI', ['ngSanitize', 'ui.router', 'SOGo.Common', 'SOGo.MailerUI', 'SOGo.UIDesktop', 'SOGo.UI', 'SOGo.ContactsUI', 'SOGo.Authentication'])
|
||||
|
||||
.constant('sgSettings', {
|
||||
baseURL: ApplicationBaseURL,
|
||||
activeUser: {
|
||||
login: UserLogin,
|
||||
identification: UserIdentification,
|
||||
language: UserLanguage,
|
||||
folderURL: UserFolderURL,
|
||||
isSuperUser: IsSuperUser
|
||||
}
|
||||
})
|
||||
|
||||
.config(['$stateProvider', '$urlRouterProvider', function($stateProvider, $urlRouterProvider) {
|
||||
$stateProvider
|
||||
.state('preferences', {
|
||||
abstract: true,
|
||||
views: {
|
||||
preferences: {
|
||||
templateUrl: 'preferences.html',
|
||||
controller: 'PreferencesCtrl'
|
||||
}
|
||||
},
|
||||
resolve: {
|
||||
statePreferences: ['sgPreferences', function(Preferences) {
|
||||
return new Preferences();
|
||||
}]
|
||||
}
|
||||
})
|
||||
.state('preferences.general', {
|
||||
url: '/general',
|
||||
views: {
|
||||
module: {
|
||||
templateUrl: 'generalPreferences.html'
|
||||
}
|
||||
}
|
||||
})
|
||||
.state('preferences.calendars', {
|
||||
url: '/calendars',
|
||||
views: {
|
||||
module: {
|
||||
templateUrl: 'calendarsPreferences.html'
|
||||
}
|
||||
}
|
||||
})
|
||||
.state('preferences.addressbooks', {
|
||||
url: '/addressbooks',
|
||||
views: {
|
||||
module: {
|
||||
templateUrl: 'addressbooksPreferences.html'
|
||||
}
|
||||
}
|
||||
})
|
||||
.state('preferences.mailer', {
|
||||
url: '/mailer',
|
||||
views: {
|
||||
module: {
|
||||
templateUrl: 'mailerPreferences.html'
|
||||
}
|
||||
}
|
||||
})
|
||||
// if none of the above states are matched, use this as the fallback
|
||||
$urlRouterProvider.otherwise('/general');
|
||||
}])
|
||||
|
||||
.controller('PreferencesCtrl', ['$scope', '$timeout', '$q', '$mdDialog', 'sgPreferences', 'sgUser', 'statePreferences', 'Authentication', function($scope, $timeout, $q, $mdDialog, Preferences, User, statePreferences, Authentication) {
|
||||
|
||||
$scope.preferences = statePreferences;
|
||||
|
||||
$scope.addCalendarCategory = function() {
|
||||
$scope.preferences.defaults.SOGoCalendarCategoriesColors["New category"] = "#aaa";
|
||||
$scope.preferences.defaults.SOGoCalendarCategories.push("New category");
|
||||
}
|
||||
|
||||
$scope.removeCalendarCategory = function(index) {
|
||||
var key = $scope.preferences.defaults.SOGoCalendarCategories[index];
|
||||
$scope.preferences.defaults.SOGoCalendarCategories.splice(index, 1);
|
||||
delete $scope.preferences.defaults.SOGoCalendarCategoriesColors[key];
|
||||
}
|
||||
|
||||
$scope.addContactCategory = function() {
|
||||
$scope.preferences.defaults.SOGoContactsCategories.push("");
|
||||
};
|
||||
|
||||
$scope.removeContactCategory = function(index) {
|
||||
$scope.preferences.defaults.SOGoContactsCategories.splice(index, 1);
|
||||
}
|
||||
|
||||
$scope.addMailAccount = function(ev) {
|
||||
$scope.preferences.defaults.AuxiliaryMailAccounts.push({});
|
||||
var account = _.last($scope.preferences.defaults.AuxiliaryMailAccounts);
|
||||
account['name'] = "New account";
|
||||
account['identities'] = [];
|
||||
account['identities'][0] = {};
|
||||
account['identities'][0]['fullName'] = "";
|
||||
account['identities'][0]['email'] = "";
|
||||
account['receipts'] = {};
|
||||
account['receipts']['receiptAction'] = "ignore";
|
||||
account['receipts']['receiptNonRecipientAction'] = "ignore";
|
||||
account['receipts']['receiptOutsideDomainAction'] = "ignore";
|
||||
account['receipts']['receiptAnyAction'] = "ignore";
|
||||
|
||||
$mdDialog.show({
|
||||
controller: AccountDialogCtrl,
|
||||
templateUrl: 'editAccount?account=new',
|
||||
targetEvent: ev,
|
||||
locals: { account: account,
|
||||
accountId: ($scope.preferences.defaults.AuxiliaryMailAccounts.length-1),
|
||||
mailCustomFromEnabled: window.mailCustomFromEnabled}
|
||||
});
|
||||
};
|
||||
|
||||
$scope.editMailAccount = function(index) {
|
||||
var account = $scope.preferences.defaults.AuxiliaryMailAccounts[index];
|
||||
$mdDialog.show({
|
||||
controller: AccountDialogCtrl,
|
||||
templateUrl: 'editAccount?account=' + index,
|
||||
targetEvent: null,
|
||||
locals: { account: account,
|
||||
accountId: index,
|
||||
mailCustomFromEnabled: window.mailCustomFromEnabled}
|
||||
}).then(function() {
|
||||
$scope.preferences.defaults.AuxiliaryMailAccounts[index] = account;
|
||||
});
|
||||
};
|
||||
|
||||
$scope.removeMailAccount = function(index) {
|
||||
$scope.preferences.defaults.AuxiliaryMailAccounts.splice(index, 1);
|
||||
};
|
||||
|
||||
$scope.addMailLabel = function() {
|
||||
$scope.preferences.defaults.SOGoMailLabelsColors["new_label"] = ["New label", "#aaa"];
|
||||
};
|
||||
|
||||
$scope.removeMailLabel = function(key) {
|
||||
delete $scope.preferences.defaults.SOGoMailLabelsColors[key];
|
||||
};
|
||||
|
||||
$scope.addMailFilter = function(ev) {
|
||||
if (!$scope.preferences.defaults.SOGoSieveFilters)
|
||||
$scope.preferences.defaults.SOGoSieveFilters = [];
|
||||
|
||||
$scope.preferences.defaults.SOGoSieveFilters.push({});
|
||||
var filter = _.last($scope.preferences.defaults.SOGoSieveFilters);
|
||||
$mdDialog.show({
|
||||
controller: FiltersDialogCtrl,
|
||||
templateUrl: 'editFilter?filter=new',
|
||||
targetEvent: ev,
|
||||
locals: { filter: filter,
|
||||
mailboxes: $scope.preferences.mailboxes,
|
||||
labels: $scope.preferences.defaults.SOGoMailLabelsColors}
|
||||
});
|
||||
};
|
||||
|
||||
$scope.editMailFilter = function(index) {
|
||||
var filter = angular.copy($scope.preferences.defaults.SOGoSieveFilters[index]);
|
||||
|
||||
$mdDialog.show({
|
||||
controller: FiltersDialogCtrl,
|
||||
templateUrl: 'editFilter?filter=' + index,
|
||||
targetEvent: null,
|
||||
locals: { filter: filter,
|
||||
mailboxes: $scope.preferences.mailboxes,
|
||||
labels: $scope.preferences.defaults.SOGoMailLabelsColors }
|
||||
}).then(function() {
|
||||
$scope.preferences.defaults.SOGoSieveFilters[index] = filter;
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
$scope.removeMailFilter = function(index) {
|
||||
$scope.preferences.defaults.SOGoSieveFilters.splice(index, 1);
|
||||
};
|
||||
|
||||
$scope.userFilter = function($query) {
|
||||
var deferred = $q.defer();
|
||||
User.$filter($query).then(function(results) {
|
||||
deferred.resolve(results)
|
||||
});
|
||||
return deferred.promise;
|
||||
};
|
||||
|
||||
$scope.save = function() {
|
||||
$scope.preferences.$save();
|
||||
};
|
||||
|
||||
$scope.passwords = { newPassword: null, newPasswordConfirmation: null };
|
||||
|
||||
$scope.canChangePassword = function() {
|
||||
if ($scope.passwords.newPassword && $scope.passwords.newPassword.length > 0 &&
|
||||
$scope.passwords.newPasswordConfirmation && $scope.passwords.newPasswordConfirmation.length &&
|
||||
$scope.passwords.newPassword == $scope.passwords.newPasswordConfirmation)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
$scope.changePassword = function() {
|
||||
Authentication.changePassword($scope.passwords.newPassword).then(function() {
|
||||
var alert = $mdDialog.alert({
|
||||
title: l('Password'),
|
||||
content: l('The password was changed successfully.'),
|
||||
ok: 'OK'
|
||||
});
|
||||
$mdDialog.show( alert )
|
||||
.finally(function() {
|
||||
alert = undefined;
|
||||
});
|
||||
}, function(msg) {
|
||||
var alert = $mdDialog.alert({
|
||||
title: l('Password'),
|
||||
content: msg,
|
||||
ok: 'OK'
|
||||
});
|
||||
$mdDialog.show( alert )
|
||||
.finally(function() {
|
||||
alert = undefined;
|
||||
});
|
||||
});
|
||||
};
|
||||
}]);
|
||||
|
||||
function FiltersDialogCtrl($scope, $mdDialog, filter, mailboxes, labels) {
|
||||
$scope.filter = filter;
|
||||
$scope.mailboxes = mailboxes;
|
||||
$scope.labels = labels;
|
||||
|
||||
$scope.fieldLabels = { "subject": l("Subject"),
|
||||
"from": l("From"),
|
||||
"to": l("To"),
|
||||
"cc": l("Cc"),
|
||||
"to_or_cc": l("To or Cc"),
|
||||
"size": l("Size (Kb)"),
|
||||
"header": l("Header"),
|
||||
"body": l("Body") };
|
||||
|
||||
$scope.methodLabels = { "addflag": l("Flag the message with:"),
|
||||
"discard": l("Discard the message"),
|
||||
"fileinto": l("File the message in:"),
|
||||
"keep": l("Keep the message"),
|
||||
"redirect": l("Forward the message to:"),
|
||||
"reject": l("Send a reject message:"),
|
||||
"vacation": l("Send a vacation message"),
|
||||
"stop": l("Stop processing filter rules") };
|
||||
|
||||
$scope.numberOperatorLabels = { "under": l("is under"),
|
||||
"over": l("is over") };
|
||||
|
||||
$scope.textOperatorLabels = { "is": l("is"),
|
||||
"is_not": l("is not"),
|
||||
"contains": l("contains"),
|
||||
"contains_not": l("does not contain"),
|
||||
"matches": l("matches"),
|
||||
"matches_not": l("does not match"),
|
||||
"regex": l("matches regex"),
|
||||
"regex_not": l("does not match regex") };
|
||||
|
||||
$scope.flagLabels = { "seen": l("Seen"),
|
||||
"deleted": l("Deleted"),
|
||||
"answered": l("Answered"),
|
||||
"flagged": l("Flagged"),
|
||||
"junk": l("Junk"),
|
||||
"not_junk": l("Not Junk") };
|
||||
|
||||
$scope.cancel = function() {
|
||||
$mdDialog.cancel();
|
||||
};
|
||||
$scope.save = function() {
|
||||
$mdDialog.hide();
|
||||
};
|
||||
$scope.addMailFilterRule = function(event) {
|
||||
if (!$scope.filter.rules)
|
||||
$scope.filter.rules = [];
|
||||
|
||||
$scope.filter.rules.push({});
|
||||
}
|
||||
$scope.removeMailFilterRule = function(index) {
|
||||
$scope.filter.rules.splice(index, 1);
|
||||
};
|
||||
$scope.addMailFilterAction = function(event) {
|
||||
if (!$scope.filter.actions)
|
||||
$scope.filter.actions = [];
|
||||
|
||||
$scope.filter.actions.push({});
|
||||
}
|
||||
$scope.removeMailFilterAction = function(index) {
|
||||
$scope.filter.actions.splice(index, 1);
|
||||
};
|
||||
}
|
||||
|
||||
function AccountDialogCtrl($scope, $mdDialog, account, accountId, mailCustomFromEnabled) {
|
||||
$scope.account = account;
|
||||
$scope.accountId = accountId;
|
||||
$scope.customFromIsReadonly = function() {
|
||||
if (accountId > 0)
|
||||
return false;
|
||||
|
||||
return !mailCustomFromEnabled;
|
||||
};
|
||||
$scope.cancel = function() {
|
||||
$mdDialog.cancel();
|
||||
};
|
||||
$scope.save = function() {
|
||||
$mdDialog.hide();
|
||||
};
|
||||
}
|
||||
})();
|
|
@ -0,0 +1,159 @@
|
|||
/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* JavaScript for SOGo.SchedulerUI module */
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
angular.module('SOGo.ContactsUI', []);
|
||||
|
||||
angular.module('SOGo.SchedulerUI', ['ngSanitize', 'ui.router', 'ct.ui.router.extras.sticky', 'ct.ui.router.extras.previous', 'vs-repeat', 'SOGo.Common', 'SOGo.ContactsUI'])
|
||||
|
||||
.constant('sgSettings', {
|
||||
baseURL: ApplicationBaseURL,
|
||||
activeUser: {
|
||||
login: UserLogin,
|
||||
identification: UserIdentification,
|
||||
language: UserLanguage,
|
||||
folderURL: UserFolderURL,
|
||||
isSuperUser: IsSuperUser
|
||||
}
|
||||
})
|
||||
.config(configure)
|
||||
.run(runBlock);
|
||||
|
||||
/**
|
||||
* @ngInject
|
||||
*/
|
||||
configure.$inject = ['$stateProvider', '$urlRouterProvider'];
|
||||
function configure($stateProvider, $urlRouterProvider) {
|
||||
$stateProvider
|
||||
.state('calendars', {
|
||||
url: '/calendar',
|
||||
views: {
|
||||
calendars: {
|
||||
templateUrl: 'UIxCalMainFrame', // UI/Templates/SchedulerUI/UIxCalMainFrame.wox
|
||||
controller: 'CalendarsController',
|
||||
controllerAs: 'calendars'
|
||||
}
|
||||
},
|
||||
resolve: {
|
||||
stateCalendars: stateCalendars
|
||||
}
|
||||
})
|
||||
.state('calendars.view', {
|
||||
url: '/{view:(?:day|week|month)}/:day',
|
||||
sticky: true,
|
||||
deepStateRedirect: true,
|
||||
views: {
|
||||
calendarView: {
|
||||
templateUrl: function($stateParams) {
|
||||
// UI/Templates/SchedulerUI/UIxCalDayView.wox or
|
||||
// UI/Templates/SchedulerUI/UIxCalWeekView.wox or
|
||||
// UI/Templates/SchedulerUI/UIxCalMonthView.wox
|
||||
return $stateParams.view + 'view?day=' + $stateParams.day;
|
||||
},
|
||||
controller: 'CalendarController',
|
||||
controllerAs: 'calendar'
|
||||
}
|
||||
},
|
||||
resolve: {
|
||||
stateEventsBlocks: stateEventsBlocks
|
||||
}
|
||||
})
|
||||
.state('calendars.newComponent', {
|
||||
url: '/:calendarId/{componentType:(?:appointment|task)}/new',
|
||||
views: {
|
||||
componentEditor: {
|
||||
templateUrl: 'UIxAppointmentEditorTemplate',
|
||||
controller: 'ComponentController',
|
||||
controllerAs: 'editor'
|
||||
}
|
||||
},
|
||||
resolve: {
|
||||
stateComponent: stateNewComponent
|
||||
}
|
||||
})
|
||||
.state('calendars.component', {
|
||||
url: '/:calendarId/event/:componentId',
|
||||
views: {
|
||||
componentEditor: {
|
||||
templateUrl: 'UIxAppointmentEditorTemplate',
|
||||
controller: 'ComponentController',
|
||||
controllerAs: 'editor'
|
||||
}
|
||||
},
|
||||
// onEnter: ['$mdSidenav', function($mdSidenav) {
|
||||
// $mdSidenav('right').open()
|
||||
// .then(function() {
|
||||
// console.debug("toggle RIGHT is done");
|
||||
// });
|
||||
// }],
|
||||
resolve: {
|
||||
stateComponent: stateComponent
|
||||
}
|
||||
});
|
||||
|
||||
$urlRouterProvider.when('/calendar/day', function() {
|
||||
// If no date is specified, show today
|
||||
var now = new Date();
|
||||
return '/calendar/day/' + now.getDayString();
|
||||
})
|
||||
$urlRouterProvider.when('/calendar/week', function() {
|
||||
// If no date is specified, show today's week
|
||||
var now = new Date();
|
||||
return '/calendar/week/' + now.getDayString();
|
||||
})
|
||||
$urlRouterProvider.when('/calendar/month', function() {
|
||||
// If no date is specified, show today's month
|
||||
var now = new Date();
|
||||
return '/calendar/month/' + now.getDayString();
|
||||
});
|
||||
|
||||
// if none of the above states are matched, use this as the fallback
|
||||
$urlRouterProvider.otherwise('/calendar');
|
||||
}
|
||||
|
||||
/**
|
||||
* @ngInject
|
||||
*/
|
||||
stateCalendars.$inject = ['Calendar'];
|
||||
function stateCalendars(Calendar) {
|
||||
return Calendar.$calendars || Calendar.$findAll(window.calendarsData);
|
||||
}
|
||||
|
||||
/**
|
||||
* @ngInject
|
||||
*/
|
||||
stateEventsBlocks.$inject = ['$stateParams', 'Component'];
|
||||
function stateEventsBlocks($stateParams, Component) {
|
||||
return Component.$eventsBlocksForView($stateParams.view, $stateParams.day.asDate());
|
||||
}
|
||||
|
||||
/**
|
||||
* @ngInject
|
||||
*/
|
||||
stateNewComponent.$inject = ['$stateParams', 'Component'];
|
||||
function stateNewComponent($stateParams, Component) {
|
||||
var component = new Component({ pid: $stateParams.calendarId, type: $stateParams.componentType });
|
||||
return component;
|
||||
}
|
||||
|
||||
/**
|
||||
* @ngInject
|
||||
*/
|
||||
stateComponent.$inject = ['$stateParams', 'Calendar'];
|
||||
function stateComponent($stateParams, Calendar) {
|
||||
return Calendar.$get($stateParams.calendarId).$getComponent($stateParams.componentId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @ngInject
|
||||
*/
|
||||
runBlock.$inject = ['$rootScope'];
|
||||
function runBlock($rootScope) {
|
||||
$rootScope.$on('$routeChangeError', function(event, current, previous, rejection) {
|
||||
console.error(event, current, previous, rejection);
|
||||
});
|
||||
}
|
||||
|
||||
})();
|
|
@ -26,7 +26,7 @@
|
|||
* @desc The factory we'll use to register with Angular
|
||||
* @returns the Calendar constructor
|
||||
*/
|
||||
Calendar.$factory = ['$q', '$timeout', '$log', 'sgSettings', 'sgResource', 'sgComponent', 'sgAcl', function($q, $timeout, $log, Settings, Resource, Component, Acl) {
|
||||
Calendar.$factory = ['$q', '$timeout', '$log', 'sgSettings', 'Resource', 'Component', 'Acl', function($q, $timeout, $log, Settings, Resource, Component, Acl) {
|
||||
angular.extend(Calendar, {
|
||||
$q: $q,
|
||||
$timeout: $timeout,
|
||||
|
@ -42,7 +42,7 @@
|
|||
|
||||
/* Factory registration in Angular module */
|
||||
angular.module('SOGo.SchedulerUI')
|
||||
.factory('sgCalendar', Calendar.$factory);
|
||||
.factory('Calendar', Calendar.$factory);
|
||||
|
||||
/**
|
||||
* @memberof Calendar
|
|
@ -0,0 +1,33 @@
|
|||
/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* @ngInject
|
||||
*/
|
||||
CalendarController.$inject = ['$scope', '$state', '$stateParams', '$timeout', '$interval', '$log', 'sgFocus', 'Calendar', 'Component', 'stateEventsBlocks'];
|
||||
function CalendarController($scope, $state, $stateParams, $timeout, $interval, $log, focus, Calendar, Component, stateEventsBlocks) {
|
||||
var vm = this;
|
||||
|
||||
vm.blocks = stateEventsBlocks;
|
||||
vm.changeView = changeView;
|
||||
|
||||
// Refresh current view when the list of calendars is modified
|
||||
$scope.$on('calendars:list', function() {
|
||||
Component.$eventsBlocksForView($stateParams.view, $stateParams.day.asDate()).then(function(data) {
|
||||
vm.blocks = data;
|
||||
});
|
||||
});
|
||||
|
||||
// Change calendar's view
|
||||
function changeView($event) {
|
||||
var date = angular.element($event.currentTarget).attr('date');
|
||||
$state.go('calendars.view', { view: $stateParams.view, day: date });
|
||||
}
|
||||
}
|
||||
|
||||
angular
|
||||
.module('SOGo.SchedulerUI')
|
||||
.controller('CalendarController', CalendarController);
|
||||
})();
|
|
@ -0,0 +1,48 @@
|
|||
/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* @ngInject
|
||||
*/
|
||||
CalendarListController.$inject = ['$scope', '$rootScope', '$timeout', '$state', 'sgFocus', 'encodeUriFilter', 'Dialog', 'sgSettings', 'Calendar', 'Component', '$mdSidenav'];
|
||||
function CalendarListController($scope, $rootScope, $timeout, $state, focus, encodeUriFilter, Dialog, Settings, Calendar, Component, $mdSidenav) {
|
||||
var vm = this;
|
||||
|
||||
vm.component = Component;
|
||||
vm.componentType = null;
|
||||
vm.selectComponentType = selectComponentType;
|
||||
vm.newComponent = newComponent;
|
||||
// TODO: should reflect last state userSettings -> Calendar -> SelectedList
|
||||
vm.selectedList = 0;
|
||||
vm.selectComponentType('events');
|
||||
|
||||
// Switch between components tabs
|
||||
function selectComponentType(type, options) {
|
||||
if (options && options.reload || vm.componentType != type) {
|
||||
// TODO: save user settings (Calendar.SelectedList)
|
||||
Component.$filter(type);
|
||||
vm.componentType = type;
|
||||
}
|
||||
}
|
||||
|
||||
function newComponent() {
|
||||
var type = 'appointment';
|
||||
|
||||
if (vm.componentType == 'tasks')
|
||||
type = 'task';
|
||||
|
||||
$state.go('calendars.newComponent', { calendarId: 'personal', componentType: type });
|
||||
}
|
||||
|
||||
// Refresh current list when the list of calendars is modified
|
||||
$scope.$on('calendars:list', function() {
|
||||
Component.$filter(vm.componentType);
|
||||
});
|
||||
}
|
||||
|
||||
angular
|
||||
.module('SOGo.SchedulerUI')
|
||||
.controller('CalendarListController', CalendarListController);
|
||||
})();
|
|
@ -0,0 +1,179 @@
|
|||
/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* @ngInject
|
||||
*/
|
||||
CalendarsController.$inject = ['$scope', '$rootScope', '$stateParams', '$state', '$timeout', '$q', '$mdDialog', '$log', 'sgFocus', 'encodeUriFilter', 'Dialog', 'sgSettings', 'Calendar', 'User', 'stateCalendars'];
|
||||
function CalendarsController($scope, $rootScope, $stateParams, $state, $timeout, $q, $mdDialog, $log, focus, encodeUriFilter, Dialog, Settings, Calendar, User, stateCalendars) {
|
||||
var vm = this;
|
||||
|
||||
vm.activeUser = Settings.activeUser;
|
||||
vm.service = Calendar;
|
||||
vm.newCalendar = newCalendar;
|
||||
vm.addWebCalendar = addWebCalendar;
|
||||
vm.confirmDelete = confirmDelete;
|
||||
vm.share = share;
|
||||
vm.subscribeToFolder = subscribeToFolder;
|
||||
|
||||
// Dispatch the event named 'calendars:list' when a calendar is activated or deactivated or
|
||||
// when the color of a calendar is changed
|
||||
$scope.$watch(
|
||||
function() {
|
||||
return _.union(
|
||||
_.map(Calendar.$calendars, function(o) { return _.pick(o, ['id', 'active', 'color']) }),
|
||||
_.map(Calendar.$subscriptions, function(o) { return _.pick(o, ['id', 'active', 'color']) }),
|
||||
_.map(Calendar.$webcalendars, function(o) { return _.pick(o, ['id', 'active', 'color']) })
|
||||
);
|
||||
},
|
||||
function(newList, oldList) {
|
||||
// Identify which calendar has changed
|
||||
var ids = _.pluck(_.filter(newList, function(o, i) { return !_.isEqual(o, oldList[i]); }), 'id');
|
||||
if (ids.length > 0) {
|
||||
$log.debug(ids.join(', ') + ' changed');
|
||||
_.each(ids, function(id) {
|
||||
var calendar = Calendar.$get(id);
|
||||
calendar.$setActivation().then(function() {
|
||||
$scope.$broadcast('calendars:list');
|
||||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
true // compare for object equality
|
||||
);
|
||||
|
||||
function newCalendar(ev) {
|
||||
Dialog.prompt(l('New calendar'), l('Name of the Calendar'))
|
||||
.then(function(name) {
|
||||
var calendar = new Calendar(
|
||||
{
|
||||
name: name,
|
||||
isEditable: true,
|
||||
isRemote: false,
|
||||
owner: UserLogin
|
||||
}
|
||||
);
|
||||
Calendar.$add(calendar);
|
||||
});
|
||||
}
|
||||
|
||||
function addWebCalendar() {
|
||||
Dialog.prompt(l('Subscribe to a web calendar...'), l('URL of the Calendar'), {inputType: 'url'})
|
||||
.then(function(url) {
|
||||
Calendar.$addWebCalendar(url);
|
||||
});
|
||||
}
|
||||
|
||||
function confirmDelete(folder) {
|
||||
if (folder.isSubscription) {
|
||||
// Unsubscribe without confirmation
|
||||
folder.$delete()
|
||||
.then(function() {
|
||||
$scope.$broadcast('calendars:list');
|
||||
}, function(data, status) {
|
||||
Dialog.alert(l('An error occured while deleting the addressbook "%{0}".', folder.name),
|
||||
l(data.error));
|
||||
});
|
||||
}
|
||||
else {
|
||||
Dialog.confirm(l('Warning'), l('Are you sure you want to delete the addressbook <em>%{0}</em>?', folder.name))
|
||||
.then(function() {
|
||||
folder.$delete()
|
||||
.then(function() {
|
||||
$scope.$broadcast('calendars:list');
|
||||
}, function(data, status) {
|
||||
Dialog.alert(l('An error occured while deleting the addressbook "%{0}".', folder.name),
|
||||
l(data.error));
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function share(calendar) {
|
||||
$mdDialog.show({
|
||||
templateUrl: calendar.id + '/UIxAclEditor', // UI/Templates/UIxAclEditor.wox
|
||||
controller: CalendarACLController,
|
||||
clickOutsideToClose: true,
|
||||
escapeToClose: true,
|
||||
locals: {
|
||||
usersWithACL: calendar.$acl.$users(),
|
||||
User: User,
|
||||
folder: calendar
|
||||
}
|
||||
});
|
||||
/**
|
||||
* @ngInject
|
||||
*/
|
||||
CalendarACLController.$inject = ['$scope', '$mdDialog', 'usersWithACL', 'User', 'folder'];
|
||||
function CalendarACLController($scope, $mdDialog, usersWithACL, User, folder) {
|
||||
$scope.users = usersWithACL; // ACL users
|
||||
$scope.folder = folder;
|
||||
$scope.selectedUser = null;
|
||||
$scope.userToAdd = '';
|
||||
$scope.searchText = '';
|
||||
$scope.userFilter = function($query) {
|
||||
return User.$filter($query);
|
||||
};
|
||||
$scope.closeModal = function() {
|
||||
folder.$acl.$resetUsersRights(); // cancel changes
|
||||
$mdDialog.hide();
|
||||
};
|
||||
$scope.saveModal = function() {
|
||||
folder.$acl.$saveUsersRights().then(function() {
|
||||
$mdDialog.hide();
|
||||
}, function(data, status) {
|
||||
Dialog.alert(l('Warning'), l('An error occured please try again.'));
|
||||
});
|
||||
};
|
||||
$scope.confirmChange = function(user) {
|
||||
var confirmation = user.$confirmRights();
|
||||
if (confirmation) {
|
||||
Dialog.confirm(l('Warning'), confirmation).then(function(res) {
|
||||
if (!res)
|
||||
user.$resetRights(true);
|
||||
});
|
||||
}
|
||||
};
|
||||
$scope.removeUser = function(user) {
|
||||
folder.$acl.$removeUser(user.uid).then(function() {
|
||||
if (user.uid == $scope.selectedUser.uid)
|
||||
$scope.selectedUser = null;
|
||||
}, function(data, status) {
|
||||
Dialog.alert(l('Warning'), l('An error occured please try again.'))
|
||||
});
|
||||
};
|
||||
$scope.addUser = function(data) {
|
||||
if (data) {
|
||||
folder.$acl.$addUser(data).then(function() {
|
||||
$scope.userToAdd = '';
|
||||
$scope.searchText = '';
|
||||
}, function(error) {
|
||||
Dialog.alert(l('Warning'), error);
|
||||
});
|
||||
}
|
||||
};
|
||||
$scope.selectUser = function(user) {
|
||||
// Check if it is a different user
|
||||
if ($scope.selectedUser != user) {
|
||||
$scope.selectedUser = user;
|
||||
$scope.selectedUser.$rights();
|
||||
}
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
// Callback of sgSubscribe directive
|
||||
function subscribeToFolder(calendarData) {
|
||||
$log.debug('subscribeToFolder ' + calendarData.owner + calendarData.name);
|
||||
Calendar.$subscribe(calendarData.owner, calendarData.name).catch(function(data) {
|
||||
Dialog.alert(l('Warning'), l('An error occured please try again.'));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
angular
|
||||
.module('SOGo.SchedulerUI')
|
||||
.controller('CalendarsController', CalendarsController);
|
||||
})();
|
|
@ -31,7 +31,7 @@
|
|||
* @desc The factory we'll use to register with Angular
|
||||
* @returns the Component constructor
|
||||
*/
|
||||
Component.$factory = ['$q', '$timeout', '$log', 'sgSettings', 'sgResource', function($q, $timeout, $log, Settings, Resource) {
|
||||
Component.$factory = ['$q', '$timeout', '$log', 'sgSettings', 'Resource', function($q, $timeout, $log, Settings, Resource) {
|
||||
angular.extend(Component, {
|
||||
$q: $q,
|
||||
$timeout: $timeout,
|
||||
|
@ -49,7 +49,7 @@
|
|||
*/
|
||||
angular.module('SOGo.SchedulerUI')
|
||||
/* Factory registration in Angular module */
|
||||
.factory('sgComponent', Component.$factory);
|
||||
.factory('Component', Component.$factory);
|
||||
|
||||
/**
|
||||
* @function $filter
|
||||
|
@ -331,13 +331,29 @@
|
|||
* @return an object literal copy of the Component instance
|
||||
*/
|
||||
Component.prototype.$omit = function() {
|
||||
var component = {};
|
||||
var component = {}, date;
|
||||
angular.forEach(this, function(value, key) {
|
||||
if (key != 'constructor' && key[0] != '$') {
|
||||
component[key] = value;
|
||||
}
|
||||
});
|
||||
|
||||
component.startTime = component.startDate ? formatTime(component.startDate) : '';
|
||||
component.endTime = component.endDate ? formatTime(component.endDate) : '';
|
||||
|
||||
function formatTime(dateString) {
|
||||
// YYYY-MM-DDTHH:MM-05:00
|
||||
var date = new Date(dateString.substring(0,10) + ' ' + dateString.substring(11,16)),
|
||||
hours = date.getHours(),
|
||||
minutes = date.getMinutes();
|
||||
|
||||
if (hours < 10) hours = '0' + hours;
|
||||
if (minutes < 10) minutes = '0' + minutes;
|
||||
|
||||
return hours + ':' + minutes;
|
||||
}
|
||||
|
||||
|
||||
return component;
|
||||
};
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* @ngInject
|
||||
*/
|
||||
ComponentController.$inject = ['$scope', '$log', '$timeout', '$state', '$previousState', '$mdSidenav', '$mdDialog', 'Calendar', 'Component', 'stateCalendars', 'stateComponent'];
|
||||
function ComponentController($scope, $log, $timeout, $state, $previousState, $mdSidenav, $mdDialog, Calendar, Component, stateCalendars, stateComponent) {
|
||||
var vm = this;
|
||||
|
||||
vm.calendars = stateCalendars;
|
||||
vm.event = stateComponent;
|
||||
vm.categories = {};
|
||||
vm.editRecurrence = editRecurrence;
|
||||
vm.cancel = cancel;
|
||||
vm.save = save;
|
||||
|
||||
// Open sidenav when loading the view;
|
||||
// Return to previous state when closing the sidenav.
|
||||
$scope.$on('$viewContentLoaded', function(event) {
|
||||
$timeout(function() {
|
||||
$mdSidenav('right').open()
|
||||
.then(function() {
|
||||
$scope.$watch($mdSidenav('right').isOpen, function(isOpen, wasOpen) {
|
||||
if (!isOpen) {
|
||||
if ($previousState.get())
|
||||
$previousState.go()
|
||||
else
|
||||
$state.go('calendars');
|
||||
}
|
||||
});
|
||||
});
|
||||
}, 100); // don't ask why
|
||||
});
|
||||
|
||||
function editRecurrence($event) {
|
||||
$mdDialog.show({
|
||||
templateUrl: 'editRecurrence', // UI/Templates/SchedulerUI/UIxRecurrenceEditor.wox
|
||||
controller: RecurrenceController
|
||||
});
|
||||
function RecurrenceController() {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
function save(form) {
|
||||
if (form.$valid) {
|
||||
vm.event.$save()
|
||||
.then(function(data) {
|
||||
$scope.$emit('calendars:list');
|
||||
$mdSidenav('right').close();
|
||||
}, function(data, status) {
|
||||
$log.debug('failed');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function cancel() {
|
||||
vm.event.$reset();
|
||||
if (vm.event.isNew) {
|
||||
// Cancelling the creation of a component
|
||||
vm.event = null;
|
||||
}
|
||||
$mdSidenav('right').close();
|
||||
}
|
||||
}
|
||||
|
||||
angular
|
||||
.module('SOGo.SchedulerUI')
|
||||
.controller('ComponentController', ComponentController);
|
||||
})();
|
|
@ -0,0 +1,69 @@
|
|||
/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
/*
|
||||
* sgCalendarDayBlock - An event block to be displayed in a week
|
||||
* @memberof SOGo.Common
|
||||
* @restrict element
|
||||
* @param {object} sgBlock - the event block definition
|
||||
* @ngInject
|
||||
* @example:
|
||||
|
||||
<sg-calendar-day-block
|
||||
ng-repeat="block in blocks[day]"
|
||||
sg-block="block"/>
|
||||
*/
|
||||
function sgCalendarDayBlock() {
|
||||
return {
|
||||
restrict: 'E',
|
||||
scope: {
|
||||
block: '=sgBlock'
|
||||
},
|
||||
replace: true,
|
||||
template: [
|
||||
'<div class="event draggable">',
|
||||
' <div class="eventInside">',
|
||||
' <div class="gradient">',
|
||||
' </div>',
|
||||
' <div class="text">{{ block.component.c_title }}',
|
||||
' <span class="icons">',
|
||||
' <i ng-if="block.component.c_nextalarm" class="md-icon-alarm"></i>',
|
||||
' <i ng-if="block.component.c_classification == 1" class="md-icon-visibility-off"></i>',
|
||||
' <i ng-if="block.component.c_classification == 2" class="md-icon-vpn-key"></i>',
|
||||
' </span></div>',
|
||||
' </div>',
|
||||
' <div class="topDragGrip"></div>',
|
||||
' <div class="bottomDragGrip"></div>',
|
||||
'</div>'
|
||||
].join(''),
|
||||
link: link
|
||||
};
|
||||
|
||||
function link(scope, iElement, attrs) {
|
||||
// Compute overlapping (5%)
|
||||
var pc = 100 / scope.block.siblings,
|
||||
left = scope.block.position * pc,
|
||||
right = 100 - (scope.block.position + 1) * pc;
|
||||
|
||||
if (pc < 100) {
|
||||
if (left > 0)
|
||||
left -= 5;
|
||||
if (right > 0)
|
||||
right -= 5;
|
||||
}
|
||||
|
||||
// Set position
|
||||
iElement.css('left', left + '%');
|
||||
iElement.css('right', right + '%');
|
||||
iElement.addClass('starts' + scope.block.start);
|
||||
iElement.addClass('lasts' + scope.block.length);
|
||||
iElement.addClass('bg-folder' + scope.block.component.c_folder);
|
||||
}
|
||||
}
|
||||
|
||||
angular
|
||||
.module('SOGo.SchedulerUI')
|
||||
.directive('sgCalendarDayBlock', sgCalendarDayBlock);
|
||||
})();
|
|
@ -0,0 +1,37 @@
|
|||
/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
/*
|
||||
* sgCalendarDayTable - Build list of blocks for a specific day
|
||||
* @memberof SOGo.Common
|
||||
* @restrict element
|
||||
* @param {object} sgBlocks - the events blocks definitions for the current view
|
||||
* @param {string} sgDay - the day of the events to display
|
||||
* @ngInject
|
||||
* @example:
|
||||
|
||||
<sg-calendar-day-table
|
||||
sg-blocks="calendar.blocks"
|
||||
sg-day="20150330" />
|
||||
*/
|
||||
function sgCalendarDayTable() {
|
||||
return {
|
||||
restrict: 'E',
|
||||
scope: {
|
||||
blocks: '=sgBlocks',
|
||||
day: '@sgDay'
|
||||
},
|
||||
template: [
|
||||
'<sg-calendar-day-block class="event draggable"',
|
||||
' ng-repeat="block in blocks[day]"',
|
||||
' sg-block="block"/>'
|
||||
].join('')
|
||||
};
|
||||
}
|
||||
|
||||
angular
|
||||
.module('SOGo.SchedulerUI')
|
||||
.directive('sgCalendarDayTable', sgCalendarDayTable);
|
||||
})();
|
|
@ -0,0 +1,38 @@
|
|||
/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
/*
|
||||
* sgCalendarMonthDay - Build list of blocks for a specific day in a month
|
||||
* @memberof SOGo.Common
|
||||
* @restrict element
|
||||
* @param {object} sgBlocks - the events blocks definitions for the current view
|
||||
* @param {string} sgDay - the day of the events to display
|
||||
* @ngInject
|
||||
* @example:
|
||||
|
||||
<sg-calendar-monh-day
|
||||
sg-blocks="calendar.blocks"
|
||||
sg-day="20150408" />
|
||||
*/
|
||||
function sgCalendarMonthDay() {
|
||||
return {
|
||||
restrict: 'E',
|
||||
scope: {
|
||||
blocks: '=sgBlocks',
|
||||
day: '@sgDay'
|
||||
},
|
||||
replace: true,
|
||||
template: [
|
||||
'<sg-calendar-month-event',
|
||||
' ng-repeat="block in blocks[day]"',
|
||||
' sg-block="block"/>'
|
||||
].join('')
|
||||
};
|
||||
}
|
||||
|
||||
angular
|
||||
.module('SOGo.SchedulerUI')
|
||||
.directive('sgCalendarMonthDay', sgCalendarMonthDay);
|
||||
})();
|
|
@ -0,0 +1,50 @@
|
|||
/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
/*
|
||||
* sgCalendarMonthEvent - An event block to be displayed in a month
|
||||
* @memberof SOGo.Common
|
||||
* @restrict element
|
||||
* @param {object} sgBlock - the event block definition
|
||||
* @ngInject
|
||||
* @example:
|
||||
|
||||
<sg-calendar-month-event
|
||||
ng-repeat="block in blocks[day]"
|
||||
sg-block="block"/>
|
||||
*/
|
||||
function sgCalendarMonthEvent() {
|
||||
return {
|
||||
restrict: 'E',
|
||||
scope: {
|
||||
block: '=sgBlock'
|
||||
},
|
||||
replace: true,
|
||||
template: [
|
||||
'<div class="sg-event">',
|
||||
' <span ng-if="!block.component.c_isallday">{{ block.starthour }} - </span>',
|
||||
' {{ block.component.c_title }}',
|
||||
' <span class="icons">',
|
||||
' <i ng-if="block.component.c_nextalarm" class="md-icon-alarm"></i>',
|
||||
' <i ng-if="block.component.c_classification == 1" class="md-icon-visibility-off"></i>',
|
||||
' <i ng-if="block.component.c_classification == 2" class="md-icon-vpn-key"></i>',
|
||||
' </span>',
|
||||
' <div class="leftDragGrip"></div>',
|
||||
' <div class="rightDragGrip"></div>',
|
||||
' </div>',
|
||||
'</div>'
|
||||
].join(''),
|
||||
link: link
|
||||
};
|
||||
|
||||
function link(scope, iElement, attrs) {
|
||||
iElement.addClass('bg-folder' + scope.block.component.c_folder);
|
||||
}
|
||||
}
|
||||
|
||||
angular
|
||||
.module('SOGo.SchedulerUI')
|
||||
.directive('sgCalendarMonthEvent', sgCalendarMonthEvent);
|
||||
})();
|
|
@ -1,391 +0,0 @@
|
|||
/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* JavaScript for SOGo.SchedulerUI module */
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
angular.module('SOGo.Common', []);
|
||||
angular.module('SOGo.ContactsUI', []);
|
||||
|
||||
angular.module('SOGo.SchedulerUI', ['ngSanitize', 'ui.router', 'ct.ui.router.extras.sticky', 'ct.ui.router.extras.previous', 'vs-repeat', 'SOGo.Common', 'SOGo.UI', 'SOGo.UIDesktop', 'SOGo.ContactsUI'])
|
||||
|
||||
.constant('sgSettings', {
|
||||
baseURL: ApplicationBaseURL,
|
||||
activeUser: {
|
||||
login: UserLogin,
|
||||
identification: UserIdentification,
|
||||
language: UserLanguage,
|
||||
folderURL: UserFolderURL,
|
||||
isSuperUser: IsSuperUser
|
||||
}
|
||||
})
|
||||
|
||||
.config(['$stateProvider', '$urlRouterProvider', function($stateProvider, $urlRouterProvider) {
|
||||
$stateProvider
|
||||
.state('calendars', {
|
||||
url: '/calendar',
|
||||
views: {
|
||||
calendars: {
|
||||
templateUrl: 'UIxCalMainFrame', // UI/Templates/SchedulerUI/UIxCalMainFrame.wox
|
||||
controller: 'CalendarsController',
|
||||
controllerAs: 'calendars'
|
||||
}
|
||||
},
|
||||
resolve: {
|
||||
stateCalendars: ['sgCalendar', function(Calendar) {
|
||||
return Calendar.$calendars || Calendar.$findAll(window.calendarsData);
|
||||
}]
|
||||
}
|
||||
})
|
||||
.state('calendars.view', {
|
||||
url: '/{view:(?:day|week|month)}/:day',
|
||||
sticky: true,
|
||||
deepStateRedirect: true,
|
||||
views: {
|
||||
calendarView: {
|
||||
templateUrl: function($stateParams) {
|
||||
// UI/Templates/SchedulerUI/UIxCalDayView.wox or
|
||||
// UI/Templates/SchedulerUI/UIxCalWeekView.wox or
|
||||
// UI/Templates/SchedulerUI/UIxCalMonthView.wox
|
||||
return $stateParams.view + 'view?day=' + $stateParams.day;
|
||||
},
|
||||
controller: 'CalendarController',
|
||||
controllerAs: 'calendar'
|
||||
}
|
||||
},
|
||||
resolve: {
|
||||
stateEventsBlocks: ['$stateParams', 'sgComponent', function($stateParams, Component) {
|
||||
return Component.$eventsBlocksForView($stateParams.view, $stateParams.day.asDate());
|
||||
}]
|
||||
}
|
||||
})
|
||||
.state('calendars.newComponent', {
|
||||
url: '/:calendarId/{componentType:(?:appointment|task)}/new',
|
||||
views: {
|
||||
componentEditor: {
|
||||
templateUrl: 'UIxAppointmentEditorTemplate',
|
||||
controller: 'ComponentController',
|
||||
controllerAs: 'editor'
|
||||
}
|
||||
},
|
||||
resolve: {
|
||||
stateComponent: ['$stateParams', 'sgComponent', function($stateParams, Component) {
|
||||
var component = new Component({ pid: $stateParams.calendarId, type: $stateParams.componentType });
|
||||
return component;
|
||||
}]
|
||||
}
|
||||
})
|
||||
.state('calendars.component', {
|
||||
url: '/:calendarId/event/:componentId',
|
||||
views: {
|
||||
componentEditor: {
|
||||
templateUrl: 'UIxAppointmentEditorTemplate',
|
||||
controller: 'ComponentController',
|
||||
controllerAs: 'editor'
|
||||
}
|
||||
},
|
||||
resolve: {
|
||||
stateComponent: ['$stateParams', 'sgCalendar', function($stateParams, Calendar) {
|
||||
return Calendar.$get($stateParams.calendarId).$getComponent($stateParams.componentId);
|
||||
}]
|
||||
}
|
||||
});
|
||||
|
||||
$urlRouterProvider.when('/calendar/day', function() {
|
||||
// If no date is specified, show today
|
||||
var now = new Date();
|
||||
return '/calendar/day/' + now.getDayString();
|
||||
})
|
||||
$urlRouterProvider.when('/calendar/week', function() {
|
||||
// If no date is specified, show today's week
|
||||
var now = new Date();
|
||||
return '/calendar/week/' + now.getDayString();
|
||||
})
|
||||
$urlRouterProvider.when('/calendar/month', function() {
|
||||
// If no date is specified, show today's month
|
||||
var now = new Date();
|
||||
return '/calendar/month/' + now.getDayString();
|
||||
});
|
||||
|
||||
// if none of the above states are matched, use this as the fallback
|
||||
$urlRouterProvider.otherwise('/calendar');
|
||||
}])
|
||||
|
||||
.run(function($rootScope) {
|
||||
$rootScope.$on('$routeChangeError', function(event, current, previous, rejection) {
|
||||
console.error(event, current, previous, rejection)
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
.controller('CalendarsController', ['$scope', '$rootScope', '$stateParams', '$state', '$timeout', '$q', '$mdDialog', '$log', 'sgFocus', 'encodeUriFilter', 'sgDialog', 'sgSettings', 'sgCalendar', 'sgUser', 'stateCalendars', function($scope, $rootScope, $stateParams, $state, $timeout, $q, $mdDialog, $log, focus, encodeUriFilter, Dialog, Settings, Calendar, User, stateCalendars) {
|
||||
var vm = this;
|
||||
|
||||
vm.activeUser = Settings.activeUser;
|
||||
vm.service = Calendar;
|
||||
|
||||
// Dispatch the event named 'calendars:list' when a calendar is activated or deactivated or
|
||||
// when the color of a calendar is changed
|
||||
$scope.$watch(
|
||||
function() {
|
||||
return _.union(
|
||||
_.map(Calendar.$calendars, function(o) { return _.pick(o, ['id', 'active', 'color']) }),
|
||||
_.map(Calendar.$subscriptions, function(o) { return _.pick(o, ['id', 'active', 'color']) }),
|
||||
_.map(Calendar.$webcalendars, function(o) { return _.pick(o, ['id', 'active', 'color']) })
|
||||
);
|
||||
},
|
||||
function(newList, oldList) {
|
||||
// Identify which calendar has changed
|
||||
var ids = _.pluck(_.filter(newList, function(o, i) { return !_.isEqual(o, oldList[i]); }), 'id');
|
||||
if (ids.length > 0) {
|
||||
$log.debug(ids.join(', ') + ' changed');
|
||||
_.each(ids, function(id) {
|
||||
var calendar = Calendar.$get(id);
|
||||
calendar.$setActivation().then(function() {
|
||||
$scope.$broadcast('calendars:list');
|
||||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
true // compare for object equality
|
||||
);
|
||||
|
||||
vm.newCalendar = function(ev) {
|
||||
Dialog.prompt(l('New calendar'), l('Name of the Calendar'))
|
||||
.then(function(name) {
|
||||
var calendar = new Calendar(
|
||||
{
|
||||
name: name,
|
||||
isEditable: true,
|
||||
isRemote: false,
|
||||
owner: UserLogin
|
||||
}
|
||||
);
|
||||
Calendar.$add(calendar);
|
||||
});
|
||||
};
|
||||
|
||||
vm.addWebCalendar = function() {
|
||||
Dialog.prompt(l('Subscribe to a web calendar...'), l('URL of the Calendar'), {inputType: 'url'})
|
||||
.then(function(url) {
|
||||
Calendar.$addWebCalendar(url);
|
||||
});
|
||||
};
|
||||
|
||||
vm.confirmDelete = function(folder) {
|
||||
if (folder.isSubscription) {
|
||||
// Unsubscribe without confirmation
|
||||
folder.$delete()
|
||||
.then(function() {
|
||||
$scope.$broadcast('calendars:list');
|
||||
}, function(data, status) {
|
||||
Dialog.alert(l('An error occured while deleting the addressbook "%{0}".', folder.name),
|
||||
l(data.error));
|
||||
});
|
||||
}
|
||||
else {
|
||||
Dialog.confirm(l('Warning'), l('Are you sure you want to delete the addressbook <em>%{0}</em>?', folder.name))
|
||||
.then(function() {
|
||||
folder.$delete()
|
||||
.then(function() {
|
||||
$scope.$broadcast('calendars:list');
|
||||
}, function(data, status) {
|
||||
Dialog.alert(l('An error occured while deleting the addressbook "%{0}".', folder.name),
|
||||
l(data.error));
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
vm.share = function(calendar) {
|
||||
$mdDialog.show({
|
||||
templateUrl: calendar.id + '/UIxAclEditor', // UI/Templates/UIxAclEditor.wox
|
||||
controller: CalendarACLController,
|
||||
clickOutsideToClose: true,
|
||||
escapeToClose: true,
|
||||
locals: {
|
||||
usersWithACL: calendar.$acl.$users(),
|
||||
User: User,
|
||||
stateCalendar: calendar
|
||||
}
|
||||
});
|
||||
function CalendarACLController($scope, $mdDialog, usersWithACL, User, stateCalendar) {
|
||||
$scope.users = usersWithACL; // ACL users
|
||||
$scope.stateCalendar = stateCalendar;
|
||||
$scope.userToAdd = '';
|
||||
$scope.searchText = '';
|
||||
$scope.userFilter = function($query) {
|
||||
return User.$filter($query);
|
||||
};
|
||||
$scope.closeModal = function() {
|
||||
stateCalendar.$acl.$resetUsersRights(); // cancel changes
|
||||
$mdDialog.hide();
|
||||
};
|
||||
$scope.saveModal = function() {
|
||||
stateCalendar.$acl.$saveUsersRights().then(function() {
|
||||
$mdDialog.hide();
|
||||
}, function(data, status) {
|
||||
Dialog.alert(l('Warning'), l('An error occured please try again.'));
|
||||
});
|
||||
};
|
||||
$scope.confirmChange = function(user) {
|
||||
var confirmation = user.$confirmRights();
|
||||
if (confirmation) {
|
||||
Dialog.confirm(l('Warning'), confirmation).then(function(res) {
|
||||
if (!res)
|
||||
user.$resetRights(true);
|
||||
});
|
||||
}
|
||||
};
|
||||
$scope.removeUser = function(user) {
|
||||
stateCalendar.$acl.$removeUser(user.uid).then(function() {
|
||||
if (user.uid == $scope.selectedUser.uid) {
|
||||
$scope.selectedUser = null;
|
||||
}
|
||||
}, function(data, status) {
|
||||
Dialog.alert(l('Warning'), l('An error occured please try again.'))
|
||||
});
|
||||
};
|
||||
$scope.addUser = function(data) {
|
||||
stateCalendar.$acl.$addUser(data).then(function() {
|
||||
$scope.userToAdd = '';
|
||||
$scope.searchText = '';
|
||||
}, function(error) {
|
||||
Dialog.alert(l('Warning'), error);
|
||||
});
|
||||
};
|
||||
$scope.selectUser = function(user) {
|
||||
// Check if it is a different user
|
||||
if ($scope.selectedUser != user) {
|
||||
$scope.selectedUser = user;
|
||||
$scope.selectedUser.$rights();
|
||||
}
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
// Callback of sgSubscribe directive
|
||||
vm.subscribeToFolder = function(calendarData) {
|
||||
$log.debug('subscribeToFolder ' + calendarData.owner + calendarData.name);
|
||||
Calendar.$subscribe(calendarData.owner, calendarData.name).catch(function(data) {
|
||||
Dialog.alert(l('Warning'), l('An error occured please try again.'));
|
||||
});
|
||||
};
|
||||
}])
|
||||
|
||||
.controller('CalendarListController', ['$scope', '$rootScope', '$timeout', '$state', 'sgFocus', 'encodeUriFilter', 'sgDialog', 'sgSettings', 'sgCalendar', 'sgComponent', '$mdSidenav', function($scope, $rootScope, $timeout, $state, focus, encodeUriFilter, Dialog, Settings, Calendar, Component, $mdSidenav) {
|
||||
var vm = this;
|
||||
|
||||
vm.component = Component;
|
||||
vm.componentType = null;
|
||||
vm.selectComponentType = selectComponentType;
|
||||
vm.newComponent = newComponent;
|
||||
// TODO: should reflect last state userSettings -> Calendar -> SelectedList
|
||||
vm.selectedList = 0;
|
||||
vm.selectComponentType('events');
|
||||
|
||||
// Switch between components tabs
|
||||
function selectComponentType(type, options) {
|
||||
if (options && options.reload || vm.componentType != type) {
|
||||
// TODO: save user settings (Calendar.SelectedList)
|
||||
Component.$filter(type);
|
||||
vm.componentType = type;
|
||||
}
|
||||
}
|
||||
|
||||
function newComponent() {
|
||||
var type = 'appointment';
|
||||
|
||||
if (vm.componentType == 'tasks')
|
||||
type = 'task';
|
||||
|
||||
$state.go('calendars.newComponent', { calendarId: 'personal', componentType: type });
|
||||
}
|
||||
|
||||
// Refresh current list when the list of calendars is modified
|
||||
$scope.$on('calendars:list', function() {
|
||||
Component.$filter(vm.componentType);
|
||||
});
|
||||
}])
|
||||
|
||||
.controller('CalendarController', ['$scope', '$state', '$stateParams', '$timeout', '$interval', '$log', 'sgFocus', 'sgCalendar', 'sgComponent', 'stateEventsBlocks', function($scope, $state, $stateParams, $timeout, $interval, $log, focus, Calendar, Component, stateEventsBlocks) {
|
||||
var vm = this;
|
||||
|
||||
vm.blocks = stateEventsBlocks;
|
||||
vm.changeView = changeView;
|
||||
|
||||
// Refresh current view when the list of calendars is modified
|
||||
$scope.$on('calendars:list', function() {
|
||||
Component.$eventsBlocksForView($stateParams.view, $stateParams.day.asDate()).then(function(data) {
|
||||
vm.blocks = data;
|
||||
});
|
||||
});
|
||||
|
||||
// Change calendar's view
|
||||
function changeView($event) {
|
||||
var date = angular.element($event.currentTarget).attr('date');
|
||||
$state.go('calendars.view', { view: $stateParams.view, day: date });
|
||||
}
|
||||
}])
|
||||
|
||||
.controller('ComponentController', ['$scope', '$log', '$timeout', '$state', '$previousState', '$mdSidenav', '$mdDialog', 'sgCalendar', 'sgComponent', 'stateCalendars', 'stateComponent', function($scope, $log, $timeout, $state, $previousState, $mdSidenav, $mdDialog, Calendar, Component, stateCalendars, stateComponent) {
|
||||
var vm = this;
|
||||
|
||||
vm.calendars = stateCalendars;
|
||||
vm.event = stateComponent;
|
||||
vm.categories = {};
|
||||
vm.editRecurrence = editRecurrence;
|
||||
vm.cancel = cancel;
|
||||
vm.save = save;
|
||||
|
||||
// Open sidenav when loading the view;
|
||||
// Return to previous state when closing the sidenav.
|
||||
$scope.$on('$viewContentLoaded', function(event) {
|
||||
$timeout(function() {
|
||||
$mdSidenav('right').open()
|
||||
.then(function() {
|
||||
$scope.$watch($mdSidenav('right').isOpen, function(isOpen, wasOpen) {
|
||||
if (!isOpen) {
|
||||
if ($previousState.get())
|
||||
$previousState.go()
|
||||
else
|
||||
$state.go('calendars');
|
||||
}
|
||||
});
|
||||
});
|
||||
}, 100); // don't ask why
|
||||
});
|
||||
|
||||
function editRecurrence($event) {
|
||||
$mdDialog.show({
|
||||
templateUrl: 'editRecurrence', // UI/Templates/SchedulerUI/UIxRecurrenceEditor.wox
|
||||
controller: RecurrenceController
|
||||
});
|
||||
function RecurrenceController() {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
function save(form) {
|
||||
if (form.$valid) {
|
||||
vm.event.$save()
|
||||
.then(function(data) {
|
||||
$scope.$emit('calendars:list');
|
||||
$mdSidenav('right').close();
|
||||
}, function(data, status) {
|
||||
$log.debug('failed');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function cancel() {
|
||||
vm.event.$reset();
|
||||
if (vm.event.isNew) {
|
||||
// Cancelling the creation of a component
|
||||
vm.event = null;
|
||||
}
|
||||
$mdSidenav('right').close();
|
||||
}
|
||||
}]);
|
||||
|
||||
})();
|
|
@ -7,11 +7,11 @@
|
|||
"csswring": ">=3.0.0",
|
||||
"grunt": ">=0.4.1",
|
||||
"grunt-cli": ">=0.1.11",
|
||||
"grunt-contrib-compass": "^1.0.1",
|
||||
"grunt-concat-sourcemap": ">=0.4.3",
|
||||
"grunt-contrib-watch": ">=0.5.3",
|
||||
"grunt-ng-annotate": ">=0.10.0",
|
||||
"grunt-postcss": "^0.3.0",
|
||||
"grunt-sass": ">=0.18.0",
|
||||
"kss": "^2.0.2",
|
||||
"sassyjson": "^1.1.8"
|
||||
"kss": "^2.0.2"
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue