(js) Improve Preferences module
- Added constraint to timezone; - Enable save button only if form is dirty and valid; - Confirm unsaved changes before leaving.pull/205/head
parent
29ec1a8ba0
commit
65f56f47b5
1
NEWS
1
NEWS
|
@ -11,6 +11,7 @@ Enhancements
|
|||
- [web] we now "cc" delegates during invitation updates (#3195)
|
||||
- [web] new SOGoHelpURL preference to set a custom URL for SOGo help (#2768)
|
||||
- [web] now able to copy/move events and also duplicate them (#3196)
|
||||
- [web] improve preferences validation and check for unsaved changes
|
||||
|
||||
Bug fixes
|
||||
- [web] fixed missing columns in SELECT statements (PostgreSQL)
|
||||
|
|
|
@ -8,19 +8,20 @@ CommonUI_PRINCIPAL_CLASS = CommonUIProduct
|
|||
|
||||
CommonUI_LANGUAGES = Arabic Basque BrazilianPortuguese Catalan ChineseTaiwan Croatian Czech Danish Dutch English Finnish French German Hungarian Icelandic Italian Lithuanian Macedonian NorwegianBokmal NorwegianNynorsk Polish Portuguese Russian Slovak Slovenian SpanishSpain SpanishArgentina Swedish Ukrainian Welsh
|
||||
|
||||
CommonUI_OBJC_FILES += \
|
||||
CommonUIProduct.m \
|
||||
UIxPageFrame.m \
|
||||
CommonUI_OBJC_FILES += \
|
||||
CommonUIProduct.m \
|
||||
UIxPageFrame.m \
|
||||
\
|
||||
UIxAclEditor.m \
|
||||
UIxObjectActions.m \
|
||||
UIxFolderActions.m \
|
||||
UIxParentFolderActions.m \
|
||||
UIxUserRightsEditor.m \
|
||||
UIxAclEditor.m \
|
||||
UIxObjectActions.m \
|
||||
UIxFolderActions.m \
|
||||
UIxParentFolderActions.m \
|
||||
UIxUserRightsEditor.m \
|
||||
\
|
||||
UIxToolbar.m \
|
||||
UIxTopnavToolbar.m \
|
||||
UIxToolbar.m \
|
||||
\
|
||||
WODirectAction+SOGo.m \
|
||||
WODirectAction+SOGo.m \
|
||||
|
||||
CommonUI_RESOURCE_FILES += \
|
||||
product.plist
|
||||
|
|
|
@ -623,9 +623,3 @@
|
|||
|
||||
@implementation UIxSidenavToolbarTemplate
|
||||
@end
|
||||
|
||||
@interface UIxTopnavToolbarTemplate : UIxComponent
|
||||
@end
|
||||
|
||||
@implementation UIxTopnavToolbarTemplate
|
||||
@end
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
/* UIxTopnavToolbar.h - this file is part of SOGo
|
||||
*
|
||||
* Copyright (C) 2016 Inverse inc.
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This file is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef UIXTOPNAVTOOLBAR_H
|
||||
#define UIXTOPNAVTOOLBAR_H
|
||||
|
||||
#import <SOGoUI/UIxComponent.h>
|
||||
|
||||
@interface UIxTopnavToolbar : UIxComponent
|
||||
{
|
||||
NSString *navButtonClick;
|
||||
}
|
||||
|
||||
- (void) setNavButtonClick: (NSString *)_navButtonClick;
|
||||
- (NSString *) navButtonClick;
|
||||
|
||||
@end
|
||||
|
||||
#endif /* UIXTOPNAVTOOLBAR_H */
|
|
@ -0,0 +1,51 @@
|
|||
/* UIxTopnavToolbar.m - this file is part of SOGo
|
||||
*
|
||||
* Copyright (C) 2016 Inverse inc.
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This file is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#import "UIxTopnavToolbar.h"
|
||||
|
||||
@implementation UIxTopnavToolbar
|
||||
|
||||
- (id) init
|
||||
{
|
||||
if ((self = [super init]))
|
||||
{
|
||||
navButtonClick = nil;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void) dealloc
|
||||
{
|
||||
[navButtonClick release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (void) setNavButtonClick: (NSString *)_navButtonClick
|
||||
{
|
||||
ASSIGN (navButtonClick, _navButtonClick);
|
||||
}
|
||||
|
||||
- (NSString *) navButtonClick
|
||||
{
|
||||
return navButtonClick;
|
||||
}
|
||||
|
||||
@end
|
|
@ -3,6 +3,18 @@
|
|||
"Close" = "Close";
|
||||
"Preferences saved" = "Preferences saved";
|
||||
|
||||
/* Unsaved changes confirmation dialog title */
|
||||
"Unsaved Changes" = "Unsaved Changes";
|
||||
|
||||
/* Unsaved changes confirmation dialog text */
|
||||
"Do you want to save your changes made to the configuration?" = "Do you want to save your changes made to the configuration?";
|
||||
|
||||
/* Unsaved changes confirmation dialog button */
|
||||
"Save" = "Save";
|
||||
|
||||
/* Unsaved changes confirmation dialog button */
|
||||
"Don't Save" = "Don't Save";
|
||||
|
||||
/* tabs */
|
||||
"General" = "General";
|
||||
"Calendar Options" = "Calendar Options";
|
||||
|
@ -87,6 +99,9 @@
|
|||
"timeFmt_3" = "";
|
||||
"timeFmt_4" = "";
|
||||
|
||||
/* Timezone autocompletion */
|
||||
"No matches found." = "No matches found.";
|
||||
|
||||
/* calendar */
|
||||
"Week begins on" = "Week begins on";
|
||||
"Day start time" = "Day start time";
|
||||
|
|
|
@ -10,9 +10,7 @@
|
|||
title="title"
|
||||
const:jsFiles="Common.js, vendor/ng-sortable.js, Preferences.js, Preferences.services.js, Mailer.services.js, Contacts.services.js, vendor/ckeditor/ckeditor.js, vendor/ckeditor/ck.js">
|
||||
|
||||
<main class="view"
|
||||
layout="row" layout-fill="layout-fill"
|
||||
ui-view="preferences"
|
||||
<main layout-fill="layout-fill" ui-view="preferences"
|
||||
ng-controller="navController"><!-- preferences --> </main>
|
||||
|
||||
<script type="text/javascript">
|
||||
|
@ -26,34 +24,40 @@
|
|||
</script>
|
||||
|
||||
<script type="text/ng-template" id="preferences.html">
|
||||
<form name="preferencesForm" class="view"
|
||||
layout="row" layout-fill="layout-fill">
|
||||
<md-sidenav id="left-sidenav" class="md-sidenav-left md-whiteframe-z1" layout="column"
|
||||
md-component-id="left" md-is-locked-open="isGtMedium"
|
||||
ng-class="{ 'sg-close': leftIsClose }">
|
||||
<var:component className="UIxSidenavToolbarTemplate" />
|
||||
<md-content md-scroll-y="md-scroll-y" class="md-flex md-hue-2">
|
||||
<md-list>
|
||||
<md-list-item ng-click="app.go('general')"
|
||||
<md-list-item ng-click="app.go('general', preferencesForm)"
|
||||
ng-disabled="preferencesForm.$invalid"
|
||||
ui-sref="preferences.general"
|
||||
ui-sref-active="md-default-theme md-background md-bg md-hue-1">
|
||||
<md-icon>settings</md-icon>
|
||||
<p class="sg-item-name"><var:string label:value="General"/></p>
|
||||
</md-list-item>
|
||||
<var:if condition="userHasCalendarAccess">
|
||||
<md-list-item ng-click="app.go('calendars')"
|
||||
<md-list-item ng-click="app.go('calendars', preferencesForm)"
|
||||
ng-disabled="preferencesForm.$invalid"
|
||||
ui-sref="preferences.calendars"
|
||||
ui-sref-active="md-default-theme md-background md-bg md-hue-1">
|
||||
<md-icon>event</md-icon>
|
||||
<p class="sg-item-name"><var:string label:value="Calendar"/></p>
|
||||
</md-list-item>
|
||||
</var:if>
|
||||
<md-list-item ng-click="app.go('addressbooks')"
|
||||
<md-list-item ng-click="app.go('addressbooks', preferencesForm)"
|
||||
ng-disabled="preferencesForm.$invalid"
|
||||
ui-sref="preferences.addressbooks"
|
||||
ui-sref-active="md-default-theme md-background md-bg md-hue-1">
|
||||
<md-icon>contacts</md-icon>
|
||||
<p class="sg-item-name"><var:string label:value="Contacts"/></p>
|
||||
</md-list-item>
|
||||
<var:if condition="userHasMailAccess">
|
||||
<md-list-item ng-click="app.go('mailer')"
|
||||
<md-list-item ng-click="app.go('mailer', preferencesForm)"
|
||||
ng-disabled="preferencesForm.$invalid"
|
||||
ui-sref="preferences.mailer"
|
||||
ui-sref-active="md-default-theme md-background md-bg md-hue-1">
|
||||
<md-icon>email</md-icon>
|
||||
|
@ -68,18 +72,20 @@
|
|||
|
||||
<!-- TOP RIGHT TOOLBAR -->
|
||||
<md-toolbar layout="row" layout-align="space-between start" class="md-tall">
|
||||
<var:component className="UIxTopnavToolbarTemplate" />
|
||||
<var:component className="UIxTopnavToolbarTemplate" const:navButtonClick="app.confirmChanges($event, preferencesForm)"/>
|
||||
<md-button type="button" class="md-fab md-fab-bottom-right md-fab-overlap-bottom"
|
||||
ng-click="app.save()">
|
||||
ng-disabled="preferencesForm.$invalid || preferencesForm.$pristine"
|
||||
ng-click="app.save(preferencesForm)">
|
||||
<md-icon>save</md-icon>
|
||||
</md-button>
|
||||
</md-toolbar>
|
||||
|
||||
<md-content>
|
||||
<md-content layout="column">
|
||||
<div ui-view="module"><!-- view --></div>
|
||||
</md-content>
|
||||
</section>
|
||||
|
||||
</form>
|
||||
</script>
|
||||
|
||||
<!--
|
||||
|
@ -104,7 +110,7 @@
|
|||
<md-input-container class="md-block" flex="50">
|
||||
<label><var:string label:value="Language"/></label>
|
||||
<md-select ng-model="app.preferences.defaults.SOGoLanguage"
|
||||
ng-change="app.onLanguageChange()">
|
||||
ng-change="app.onLanguageChange(preferencesForm)">
|
||||
<var:foreach list="languages" item="item">
|
||||
<md-option var:value="item">
|
||||
<var:string value="languageText"/>
|
||||
|
@ -114,15 +120,22 @@
|
|||
</md-input-container>
|
||||
<md-autocomplete
|
||||
class="md-block" flex="50"
|
||||
style="padding-bottom: 0"
|
||||
md-search-text="app.timeZonesSearchText"
|
||||
md-selected-item="app.preferences.defaults.SOGoTimeZone"
|
||||
md-items="timezone in app.timeZonesListFilter(app.timeZonesSearchText)"
|
||||
md-item-text="timezone"
|
||||
md-min-length="3"
|
||||
md-select-on-match="true"
|
||||
md-match-case-insensitive="true"
|
||||
ng-required="true"
|
||||
sg-select-only="sg-select-only"
|
||||
label:md-floating-label="Current Time Zone">
|
||||
<span md-highlight-text="app.timeZonesSearchText">{{timezone}}</span>
|
||||
<md-item-template>
|
||||
<span md-highlight-text="app.timeZonesSearchText">{{timezone}}</span>
|
||||
</md-item-template>
|
||||
<md-not-found>
|
||||
<var:string label:value="No matches found."/>
|
||||
</md-not-found>
|
||||
</md-autocomplete>
|
||||
</div>
|
||||
|
||||
|
@ -365,7 +378,7 @@
|
|||
<md-button class="sg-icon-button" type="button"
|
||||
layout="row" layout-align="end center"
|
||||
label:aria-label="Remove Calendar Category"
|
||||
ng-click="app.removeCalendarCategory($index)">
|
||||
ng-click="app.removeCalendarCategory($index, preferencesForm)">
|
||||
<md-icon>remove_circle</md-icon>
|
||||
</md-button>
|
||||
</md-list-item>
|
||||
|
@ -374,7 +387,7 @@
|
|||
<div layout="row" layout-align="end center">
|
||||
<md-button type="button"
|
||||
label:aria-label="Add Calendar Category"
|
||||
ng-click="app.addCalendarCategory()">
|
||||
ng-click="app.addCalendarCategory(preferencesForm)">
|
||||
<var:string label:value="Add Calendar Category"/>
|
||||
</md-button>
|
||||
</div>
|
||||
|
@ -586,7 +599,7 @@
|
|||
ng-show="app.preferences.defaults.SOGoMailComposeMessageType == 'html'">
|
||||
<md-checkbox
|
||||
ng-model="app.preferences.defaults.SOGoMailComposeFontSizeEnabled"
|
||||
label:aria-label="Default font size">
|
||||
label:aria-label="Default font size"><!-- default font size -->
|
||||
</md-checkbox>
|
||||
<md-input-container class="md-block md-flex">
|
||||
<label><var:string label:value="Default font size"/></label>
|
||||
|
@ -655,13 +668,13 @@
|
|||
<input type="text" ng-model="app.preferences.defaults.SOGoSieveFilters[$index].name"/>
|
||||
</md-input-container>
|
||||
<md-button class="sg-icon-button" type="button"
|
||||
ng-click="app.editMailFilter($event, $index)"
|
||||
ng-click="app.editMailFilter($event, $index, preferencesForm)"
|
||||
layout="row" layout-align="end center"
|
||||
label:aria-label="Edit Filter">
|
||||
<md-icon>edit</md-icon>
|
||||
</md-button>
|
||||
<md-button class="sg-icon-button" type="button"
|
||||
ng-click="app.removeMailFilter($index)"
|
||||
ng-click="app.removeMailFilter($index, preferencesForm)"
|
||||
layout="row" layout-align="end center"
|
||||
label:aria-label="Delete Filter">
|
||||
<md-icon>remove_circle</md-icon>
|
||||
|
@ -672,7 +685,7 @@
|
|||
<!-- FIXME: move up/down to be replaced by DnD? -->
|
||||
<div layout="row" layout-align="end center">
|
||||
<md-button type="button"
|
||||
ng-click="app.addMailFilter($event)"
|
||||
ng-click="app.addMailFilter($event, preferencesForm)"
|
||||
label:aria-label="Create Filter">
|
||||
<var:string label:value="Create Filter"/>
|
||||
</md-button>
|
||||
|
@ -700,7 +713,7 @@
|
|||
<md-button class="md-icon-button" type="button"
|
||||
layout="row" layout-align="end center"
|
||||
label:aria-label="Delete Label"
|
||||
ng-click="app.removeMailLabel(key)">
|
||||
ng-click="app.removeMailLabel(key, preferencesForm)">
|
||||
<md-icon>remove_circle</md-icon>
|
||||
</md-button>
|
||||
</md-list-item>
|
||||
|
@ -709,7 +722,7 @@
|
|||
<div layout="row" layout-align="end center">
|
||||
<md-button type="button"
|
||||
label:aria-label="Create Label"
|
||||
ng-click="app.addMailLabel()">
|
||||
ng-click="app.addMailLabel(preferencesForm)">
|
||||
<var:string label:value="Create Label"/>
|
||||
</md-button>
|
||||
</div>
|
||||
|
@ -794,7 +807,7 @@
|
|||
const:id="autoReplyEmailAddresses"
|
||||
ng-model="app.preferences.defaults.Vacation.autoReplyEmailAddresses"/>
|
||||
</md-input-container>
|
||||
<md-button ng-click="app.addDefaultEmailAddresses()">
|
||||
<md-button ng-click="app.addDefaultEmailAddresses(preferencesForm)">
|
||||
<var:string label:value="Add default email addresses" type="button"/>
|
||||
</md-button>
|
||||
</div>
|
||||
|
|
|
@ -27,12 +27,14 @@
|
|||
<md-button class="md-icon-button"
|
||||
ng-show="activeUser.path.calendar.length"
|
||||
ng-disabled="baseURL.endsWith('/Calendar/')"
|
||||
var:ng-click="navButtonClick"
|
||||
ng-href="{{activeUser.path.calendar}}">
|
||||
<md-tooltip><var:string label:value="Calendar"/></md-tooltip>
|
||||
<md-icon>event</md-icon>
|
||||
</md-button>
|
||||
<md-button class="md-icon-button"
|
||||
ng-disabled="baseURL.endsWith('/Contacts/')"
|
||||
var:ng-click="navButtonClick"
|
||||
ng-href="{{activeUser.path.contacts}}">
|
||||
<md-icon>contacts</md-icon>
|
||||
<md-tooltip><var:string label:value="Address Book"/></md-tooltip>
|
||||
|
@ -40,6 +42,7 @@
|
|||
<md-button class="md-icon-button"
|
||||
ng-show="activeUser.path.mail.length"
|
||||
ng-disabled="baseURL.endsWith('/Mail/')"
|
||||
var:ng-click="navButtonClick"
|
||||
ng-href="{{activeUser.path.mail}}">
|
||||
<md-icon>email</md-icon>
|
||||
<md-tooltip><var:string label:value="Mail"/></md-tooltip>
|
||||
|
@ -47,6 +50,7 @@
|
|||
<md-button class="md-icon-button"
|
||||
ng-disabled="baseURL.endsWith('/Administration/')"
|
||||
ng-show="activeUser.isSuperUser"
|
||||
var:ng-click="navButtonClick"
|
||||
ng-href="{{activeUser.path.administration}}">
|
||||
<md-icon>settings_applications</md-icon>
|
||||
<md-tooltip><var:string label:value="Administration"/></md-tooltip>
|
||||
|
@ -62,6 +66,7 @@
|
|||
</md-button>
|
||||
<md-button class="md-icon-button"
|
||||
ng-show="activeUser.path.logoff.length"
|
||||
var:ng-click="navButtonClick"
|
||||
ng-href="{{activeUser.path.logoff}}">
|
||||
<md-icon>settings_power</md-icon>
|
||||
<md-tooltip><var:string label:value="Disconnect"/></md-tooltip>
|
|
@ -0,0 +1,49 @@
|
|||
/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* sgSelectOnly - A directive that restricts an autocomplete field to its selectable values.
|
||||
* @memberof SOGo.Common
|
||||
* @ngInject
|
||||
* @example:
|
||||
|
||||
<md-autocomplete
|
||||
md-items="timezone in timeZones"
|
||||
ng-required="true"
|
||||
sg-select-only>
|
||||
*/
|
||||
function sgSelectOnly() {
|
||||
return {
|
||||
link: postLink,
|
||||
require: 'mdAutocomplete',
|
||||
restrict: 'A'
|
||||
};
|
||||
|
||||
function postLink(scope, element, attrs, autoComplete) {
|
||||
function getInput() {
|
||||
return element.find('input').eq(0);
|
||||
}
|
||||
|
||||
// We need to wait for the autocomplete directive to be compiled
|
||||
var listener = scope.$watch(getInput, function (input) {
|
||||
var ngModel;
|
||||
|
||||
if (input.length) {
|
||||
listener(); // self release
|
||||
ngModel = input.controller('ngModel');
|
||||
input.on('blur', function () {
|
||||
if (!autoComplete.scope.selectedItem) {
|
||||
scope.$applyAsync(ngModel.$setValidity('required', false));
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
angular
|
||||
.module('SOGo.Common')
|
||||
.directive('sgSelectOnly', sgSelectOnly);
|
||||
})();
|
|
@ -30,6 +30,7 @@
|
|||
vm.removeMailFilter = removeMailFilter;
|
||||
vm.addDefaultEmailAddresses = addDefaultEmailAddresses;
|
||||
vm.userFilter = User.$filter;
|
||||
vm.confirmChanges = confirmChanges;
|
||||
vm.save = save;
|
||||
vm.canChangePassword = canChangePassword;
|
||||
vm.changePassword = changePassword;
|
||||
|
@ -55,46 +56,52 @@
|
|||
User.$alternateAvatar = statePreferences.defaults.SOGoAlternateAvatar;
|
||||
});
|
||||
|
||||
function go(module) {
|
||||
// Close sidenav on small devices
|
||||
if ($mdMedia('xs'))
|
||||
$mdSidenav('left').close();
|
||||
$state.go('preferences.' + module);
|
||||
function go(module, form) {
|
||||
if (form.$valid) {
|
||||
// Close sidenav on small devices
|
||||
if ($mdMedia('xs'))
|
||||
$mdSidenav('left').close();
|
||||
$state.go('preferences.' + module);
|
||||
}
|
||||
}
|
||||
|
||||
function onLanguageChange() {
|
||||
function onLanguageChange(form) {
|
||||
Dialog.confirm(l('Warning'),
|
||||
l('Save preferences and reload page now?'),
|
||||
{ok: l('Yes'), cancel: l('No')})
|
||||
.then(function() {
|
||||
save().then(function() {
|
||||
save(form, { quick: true }).then(function() {
|
||||
$window.location.reload(true);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function addCalendarCategory() {
|
||||
function addCalendarCategory(form) {
|
||||
vm.preferences.defaults.SOGoCalendarCategoriesColors["New category"] = "#aaa";
|
||||
vm.preferences.defaults.SOGoCalendarCategories.push("New category");
|
||||
focus('calendarCategory_' + (vm.preferences.defaults.SOGoCalendarCategories.length - 1));
|
||||
form.$setDirty();
|
||||
}
|
||||
|
||||
function removeCalendarCategory(index) {
|
||||
function removeCalendarCategory(index, form) {
|
||||
var key = vm.preferences.defaults.SOGoCalendarCategories[index];
|
||||
vm.preferences.defaults.SOGoCalendarCategories.splice(index, 1);
|
||||
delete vm.preferences.defaults.SOGoCalendarCategoriesColors[key];
|
||||
form.$setDirty();
|
||||
}
|
||||
|
||||
function addContactCategory() {
|
||||
function addContactCategory(form) {
|
||||
vm.preferences.defaults.SOGoContactsCategories.push("");
|
||||
focus('contactCategory_' + (vm.preferences.defaults.SOGoContactsCategories.length - 1));
|
||||
form.$setDirty();
|
||||
}
|
||||
|
||||
function removeContactCategory(index) {
|
||||
function removeContactCategory(index, form) {
|
||||
vm.preferences.defaults.SOGoContactsCategories.splice(index, 1);
|
||||
form.$setDirty();
|
||||
}
|
||||
|
||||
function addMailAccount(ev) {
|
||||
function addMailAccount(ev, form) {
|
||||
var account;
|
||||
|
||||
vm.preferences.defaults.AuxiliaryMailAccounts.push({});
|
||||
|
@ -125,10 +132,12 @@
|
|||
accountId: (vm.preferences.defaults.AuxiliaryMailAccounts.length-1),
|
||||
mailCustomFromEnabled: window.mailCustomFromEnabled
|
||||
}
|
||||
}).then(function() {
|
||||
form.$setDirty();
|
||||
});
|
||||
}
|
||||
|
||||
function editMailAccount(event, index) {
|
||||
function editMailAccount(event, index, form) {
|
||||
var account = vm.preferences.defaults.AuxiliaryMailAccounts[index];
|
||||
$mdDialog.show({
|
||||
controller: 'AccountDialogController',
|
||||
|
@ -143,24 +152,28 @@
|
|||
}
|
||||
}).then(function() {
|
||||
vm.preferences.defaults.AuxiliaryMailAccounts[index] = account;
|
||||
form.$setDirty();
|
||||
});
|
||||
}
|
||||
|
||||
function removeMailAccount(index) {
|
||||
function removeMailAccount(index, form) {
|
||||
vm.preferences.defaults.AuxiliaryMailAccounts.splice(index, 1);
|
||||
form.$setDirty();
|
||||
}
|
||||
|
||||
function addMailLabel() {
|
||||
function addMailLabel(form) {
|
||||
// See $omit() in the Preferences services for real key generation
|
||||
var key = '_$$' + guid();
|
||||
vm.preferences.defaults.SOGoMailLabelsColors[key] = ["New label", "#aaa"];
|
||||
form.$setDirty();
|
||||
}
|
||||
|
||||
function removeMailLabel(key) {
|
||||
function removeMailLabel(key, form) {
|
||||
delete vm.preferences.defaults.SOGoMailLabelsColors[key];
|
||||
form.$setDirty();
|
||||
}
|
||||
|
||||
function addMailFilter(ev) {
|
||||
function addMailFilter(ev, form) {
|
||||
var filter = { match: 'all' };
|
||||
|
||||
$mdDialog.show({
|
||||
|
@ -177,10 +190,11 @@
|
|||
if (!vm.preferences.defaults.SOGoSieveFilters)
|
||||
vm.preferences.defaults.SOGoSieveFilters = [];
|
||||
vm.preferences.defaults.SOGoSieveFilters.push(filter);
|
||||
form.$setDirty();
|
||||
});
|
||||
}
|
||||
|
||||
function editMailFilter(ev, index) {
|
||||
function editMailFilter(ev, index, form) {
|
||||
var filter = angular.copy(vm.preferences.defaults.SOGoSieveFilters[index]);
|
||||
|
||||
$mdDialog.show({
|
||||
|
@ -195,14 +209,16 @@
|
|||
}
|
||||
}).then(function() {
|
||||
vm.preferences.defaults.SOGoSieveFilters[index] = filter;
|
||||
form.$setDirty();
|
||||
});
|
||||
}
|
||||
|
||||
function removeMailFilter(index) {
|
||||
function removeMailFilter(index, form) {
|
||||
vm.preferences.defaults.SOGoSieveFilters.splice(index, 1);
|
||||
form.$setDirty();
|
||||
}
|
||||
|
||||
function addDefaultEmailAddresses() {
|
||||
function addDefaultEmailAddresses(form) {
|
||||
var v = [];
|
||||
|
||||
if (angular.isDefined(vm.preferences.defaults.Vacation.autoReplyEmailAddresses)) {
|
||||
|
@ -210,9 +226,38 @@
|
|||
}
|
||||
|
||||
vm.preferences.defaults.Vacation.autoReplyEmailAddresses = (_.union(window.defaultEmailAddresses.split(','), v)).join(',');
|
||||
form.$setDirty();
|
||||
}
|
||||
|
||||
function save() {
|
||||
|
||||
function confirmChanges($event, form) {
|
||||
var target;
|
||||
|
||||
if (form.$dirty) {
|
||||
// Stop default action
|
||||
$event.preventDefault();
|
||||
$event.stopPropagation();
|
||||
|
||||
// Find target link
|
||||
target = $event.target;
|
||||
while (target.tagName != 'A')
|
||||
target = target.parentNode;
|
||||
|
||||
Dialog.confirm(l('Unsaved Changes'),
|
||||
l('Do you want to save your changes made to the configuration?'),
|
||||
{ ok: l('Save'), cancel: l('Don\'t Save') })
|
||||
.then(function() {
|
||||
// Save & follow link
|
||||
save(form, { quick: true }).then(function() {
|
||||
$window.location = target.href;
|
||||
});
|
||||
}, function() {
|
||||
// Don't save & follow link
|
||||
$window.location = target.href;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function save(form, options) {
|
||||
var i, sendForm, addresses, defaultAddresses, domains, domain;
|
||||
|
||||
sendForm = true;
|
||||
|
@ -252,21 +297,14 @@
|
|||
|
||||
if (sendForm)
|
||||
return vm.preferences.$save().then(function(data) {
|
||||
$mdToast.show({
|
||||
controller: 'savePreferencesToastCtrl',
|
||||
template: [
|
||||
'<md-toast>',
|
||||
' <div class="md-toast-content">',
|
||||
' <span flex>' + l('Preferences saved') + '</span>',
|
||||
' <md-button class="md-icon-button md-primary" ng-click="closeToast()">',
|
||||
' <md-icon>close</md-icon>',
|
||||
' </md-button>',
|
||||
' </div>',
|
||||
'</md-toast>'
|
||||
].join(''),
|
||||
hideDelay: 2000,
|
||||
position: 'top right'
|
||||
});
|
||||
if (!options || !options.quick) {
|
||||
$mdToast.show(
|
||||
$mdToast.simple()
|
||||
.content(l('Preferences saved'))
|
||||
.position('bottom right')
|
||||
.hideDelay(2000));
|
||||
form.$setPristine();
|
||||
}
|
||||
});
|
||||
|
||||
return $q.reject();
|
||||
|
@ -312,16 +350,8 @@
|
|||
}
|
||||
}
|
||||
|
||||
savePreferencesToastCtrl.$inject = ['$scope', '$mdToast'];
|
||||
function savePreferencesToastCtrl($scope, $mdToast) {
|
||||
$scope.closeToast = function() {
|
||||
$mdToast.hide();
|
||||
};
|
||||
}
|
||||
|
||||
angular
|
||||
.module('SOGo.PreferencesUI')
|
||||
.controller('savePreferencesToastCtrl', savePreferencesToastCtrl)
|
||||
.controller('PreferencesController', PreferencesController);
|
||||
|
||||
})();
|
||||
|
|
|
@ -80,11 +80,19 @@ md-list-item {
|
|||
.md-button,
|
||||
&.md-clickable {
|
||||
margin: 0;
|
||||
transition: background-color $swift-ease-in-duration $swift-ease-in-timing-function;
|
||||
transition: background-color $swift-ease-in-duration $swift-ease-in-timing-function,
|
||||
color $swift-linear-duration $swift-linear-timing-function;
|
||||
}
|
||||
|
||||
&.md-clickable:hover {
|
||||
background-color: rgba(158,158,158,0.2);
|
||||
&.md-clickable:not([disabled]):hover {
|
||||
background-color: rgba($colorGrey500, 0.2); // See button-theme.scss
|
||||
}
|
||||
|
||||
&[disabled] {
|
||||
color: rgba(0,0,0,0.38) !important; // = {{foreground-3}}; See button-theme.scss
|
||||
md-icon {
|
||||
color: rgba(0,0,0,0.38);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue