First pass at the v3 pref module

The UI needs to be styled. We also need to properly load "default"
values from the system/domain/user defaults and save them correctly
too.
This commit is contained in:
Ludovic Marcotte
2015-02-25 17:21:07 -05:00
committed by Francis Lachapelle
parent 575676deb8
commit 5c3f0138f5
15 changed files with 1792 additions and 712 deletions
+6 -1
View File
@@ -164,7 +164,7 @@
- (NSString *) relativePreferencesPath
{
return [self relativePathToUserFolderSubPath: @"preferences"];
return [self relativePathToUserFolderSubPath: @"Preferences/"];
}
- (NSString *) relativeAdministrationPath
@@ -466,6 +466,11 @@
return [self _moduleIs: @"MailerUI"];
}
- (BOOL) isPreferences
{
return [self _moduleIs: @"PreferencesUI"];
}
- (BOOL) isAdministration
{
return [self _moduleIs: @"AdministrationUI"];
+1
View File
@@ -13,6 +13,7 @@ PreferencesUI_OBJC_FILES = \
\
UIxJSONPreferences.m \
UIxPreferences.m \
UIxAccountEditor.m \
UIxFilterEditor.m \
\
UIxAdditionalPreferences.m
+102
View File
@@ -0,0 +1,102 @@
/* UIxAccountEditor.m - this file is part of SOGo
*
* Copyright (C) 2010-2015 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 <Foundation/NSCharacterSet.h>
#import <Foundation/NSDictionary.h>
#import <NGObjWeb/WORequest.h>
#import <NGObjWeb/WOResponse.h>
#import <SOGo/NSDictionary+Utilities.h>
#import <SOGo/NSString+Utilities.h>
#import <SOGo/SOGoUser.h>
#import <SOGo/SOGoUserDefaults.h>
#import <SOGo/SOGoSystemDefaults.h>
#import <SOGoUI/UIxComponent.h>
@interface UIxAccountEditor : UIxComponent
{
NSString *accountId;
}
@end
@implementation UIxAccountEditor
- (id) init
{
self = [super init];
if (self)
{
accountId = nil;
}
return self;
}
- (void) dealloc
{
RELEASE(accountId);
[super dealloc];
}
- (BOOL) _validateFilterId
{
NSCharacterSet *digits;
BOOL rc;
digits = [NSCharacterSet decimalDigitCharacterSet];
rc = ([accountId isEqualToString: @"new"]
|| [[accountId stringByTrimmingCharactersInSet: digits] length] == 0);
return rc;
}
- (id <WOActionResults>) defaultAction
{
id <WOActionResults> result;
WORequest *request;
request = [context request];
ASSIGN (accountId, [request formValueForKey: @"account"]);
if (accountId)
{
if ([self _validateFilterId])
result = self;
else
result = [self responseWithStatus: 403
andString: @"Bad value for 'account'"];
}
else
result = [self responseWithStatus: 403
andString: @"Missing 'account' parameter"];
return result;
}
- (NSString *) accountId
{
return accountId;
}
@end
+1 -1
View File
@@ -1,6 +1,6 @@
/* UIxFilterEditor.m - this file is part of SOGo
*
* Copyright (C) 2010-2014 Inverse inc.
* Copyright (C) 2010-2015 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
+1 -3
View File
@@ -1,8 +1,6 @@
/* UIxJSONPreferences.h - this file is part of SOGo
*
* Copyright (C) 2007 Inverse inc.
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
* Copyright (C) 2007-2015 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
+1 -3
View File
@@ -1,8 +1,6 @@
/* UIxJSONPreferences.m - this file is part of SOGo
*
* Copyright (C) 2007 Inverse inc.
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
* Copyright (C) 2007-2015 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
+6
View File
@@ -1887,4 +1887,10 @@ static NSArray *reminderValues = nil;
return (mailCustomFromEnabled ? @"true" : @"false");
}
- (id <WOActionResults>) saveAction
{
//return [self responseWithStatus: 200 andJSONRepresentation: data];
return [self responseWithStatus: 200];
}
@end
+10 -1
View File
@@ -15,10 +15,14 @@
};
};
methods = {
preferences = {
Preferences = {
protectedBy = "View";
pageName = "UIxPreferences";
};
editAccount = {
protectedBy = "View";
pageName = "UIxAccountEditor";
};
editFilter = {
protectedBy = "View";
pageName = "UIxFilterEditor";
@@ -37,6 +41,11 @@
actionClass = "UIxJSONPreferences";
actionName = "jsonSettings";
};
save = {
protectedBy = "Change Images And Files";
pageName = "UIxPreferences";
actionName = "save";
};
};
};
};
@@ -0,0 +1,120 @@
<?xml version="1.0" standalone="yes"?>
<!DOCTYPE var:component>
<var:component
xmlns="http://www.w3.org/1999/xhtml"
xmlns:var="http://www.skyrix.com/od/binding"
xmlns:const="http://www.skyrix.com/od/constant"
xmlns:uix="OGo:uix"
xmlns:rsrc="OGo:url"
xmlns:label="OGo:label"
className="UIxPageFrame"
title="title"
const:popup="YES"
>
<md-dialog>
<md-content>
<script type="text/javascript">
var accountId = '<var:string value="accountId"/>';
</script>
<form id="mainForm" var:href="ownPath">
<md-input-container>
<label><var:string label:value="Account Name:"/></label>
<input type="text" required="required" ng-model="account.name"/>
</md-input-container>
<md-input-container>
<label><var:string label:value="Server Name:"/></label>
<input type="text" required="required" ng-model="account.serverName"/>
</md-input-container>
<md-input-container>
<label><var:string label:value="Port:"/></label>
<input type="text" required="required"
ng-model="account.port"/>
</md-input-container>
<md-radio-group ng-model="account.encryption">
<label><var:string label:value="Encryption:"/></label>
<md-radio-button value="none"><var:string label:value="None"/></md-radio-button>
<md-radio-button value="ssl"><var:string label:value="SSL"/></md-radio-button>
<md-radio-button value="tls"><var:string label:value="TLS"/></md-radio-button>
</md-radio-group>
<md-input-container>
<label><var:string label:value="User Name:"/></label>
<input type="text" required="required" ng-model="account.userName"/>
</md-input-container>
<md-input-container>
<label><var:string label:value="Password:"/></label>
<input type="text" required="required" ng-model="account.password"/>
</md-input-container>
<script type="text/javascript">
var mailCustomFromEnabled = <var:string value="mailCustomFromEnabled" const:escapeHTML="NO"/>;
</script>
<md-input-container>
<label><var:string label:value="Full Name:"/></label>
<input type="text" required="required" ng-model="account.identities[0].fullName"/>
</md-input-container>
<md-input-container>
<label><var:string label:value="Email:"/></label>
<input type="text" required="required" ng-model="account.identities[0].email"/>
</md-input-container>
<md-input-container>
<label><var:string label:value="Reply To Email:"/></label>
<input type="text" ng-model="account.identities[0].replyTo"/>
</md-input-container>
<!-- FIXME -->
<md-input-container>
<label><var:string label:value="Signature:"/></label>
<input type="text" ng-model="account.identities[0].signature" />
</md-input-container>
<md-radio-group ng-model="account.receipts.receiptAction">
<label><var:string label:value="When I receive a request for a return receipt:"/></label>
<md-radio-button value="ignore"><var:string label:value="Never send a return receipt"/></md-radio-button>
<md-radio-button value="allow"><var:string label:value="Allow return receipts for some messages"/></md-radio-button>
</md-radio-group>
<label>
<var:string label:value="If I'm not in the To or Cc of the message:"/>
<md-select ng-model="account.receipts.receiptNonRecipientAction">
<md-option const:value="ignore"><var:string label:value="Never send"/></md-option>
<md-option const:value="send"><var:string label:value="Always send"/></md-option>
<md-option const:value="ask"><var:string label:value="Ask me"/></md-option>
</md-select>
</label>
<label>
<var:string label:value="If the sender is outside my domain:"/>
<md-select ng-model="account.receipts.receiptOutsideDomainAction">
<md-option const:value="ignore"><var:string label:value="Never send"/></md-option>
<md-option const:value="send"><var:string label:value="Always send"/></md-option>
<md-option const:value="ask"><var:string label:value="Ask me"/></md-option>
</md-select>
</label>
<label>
<var:string label:value="In all other cases:"/>
<md-select ng-model="account.receipts.receiptAnyAction">
<md-option const:value="ignore"><var:string label:value="Never send"/></md-option>
<md-option const:value="send"><var:string label:value="Always send"/></md-option>
<md-option const:value="ask"><var:string label:value="Ask me"/></md-option>
</md-select>
</label>
<div class="md-actions" layout="row">
<md-button type="button" ng-click="cancel()">Cancel</md-button>
<md-button type="button" class="md-primary" ng-click="save()">Save</md-button>
</div>
</form>
</md-content>
</md-dialog>
</var:component>
+111 -32
View File
@@ -11,6 +11,8 @@
title="title"
const:popup="YES"
>
<md-dialog>
<md-content>
<script type="text/javascript">
var filterId = '<var:string value="filterId"/>';
var sieveFolderEncoding = '<var:string value="sieveFolderEncoding"/>';
@@ -18,48 +20,125 @@
</script>
<form id="mainForm" var:href="ownPath">
<div id="filterNameContainer" class="container">
<label><var:string label:value="Filter name:"
/><input const:name="filterName" class="textField" type="text"
var:value="filterName"/></label><br/>
<md-input-container>
<label><var:string label:value="Filter name:"/></label>
<input const:name="filterName" type="text" ng-model="filter.name"/>
</md-input-container>
</div>
<div id="filterMatchContainer" class="container">
<var:string label:value="For incoming messages that"/>
<select const:name="matchType" const:id="matchType"
><option const:value="all"
><var:string label:value="match all of the following rules:"
/></option
><option const:value="any"
><var:string label:value="match any of the following rules:"
/></option
><option const:value="allmessages"
><var:string label:value="match all messages"
/></option
></select>
<md-select const:name="matchType" const:id="matchType" ng-model="filter.match">
<md-option const:value="all">
<var:string label:value="match all of the following rules:"/>
</md-option>
<md-option const:value="any">
<var:string label:value="match any of the following rules:"/>
</md-option>
<md-option const:value="allmessages">
<var:string label:value="match all messages"/>
</md-option>
</md-select>
</div>
<!-- CONDITIONS -->
<div id="filterRulesContainer" class="container">
<div id="filterRules"><!-- empty --></div>
<div class="bottomToolbar"
><a const:id="ruleAdd" class="bottomButton" href="#">
<span><img rsrc:src="add-icon.png" label:title="Add" />
</span></a
><a const:id="ruleDelete" class="bottomButton" href="#">
<span><img rsrc:src="remove-icon.png" label:title="Delete" />
</span></a
></div>
<div id="filterRules"><!-- empty -->
<md-list>
<md-item ng-repeat="rule in filter.rules">
<md-item-content>
<md-select ng-model="rule.field">
<md-option ng-value="key" ng-repeat="(key, value) in fieldLabels">{{ value }}</md-option>
</md-select>
<input type="text" ng-show="rule.field ==
'header'" ng-model="rule.custom_header"/>
<md-select ng-show="rule.field =='size'" ng-model="rule.operator">
<md-option ng-value="key" ng-repeat="(key, value) in numberOperatorLabels">
{{ value }}
</md-option>
</md-select>
<md-select ng-show="rule.field !='size'" ng-model="rule.operator">
<md-option ng-value="key" ng-repeat="(key, value) in textOperatorLabels">
{{ value }}
</md-option>
</md-select>
<input type="text" ng-model="rule.value"/>
<md-button ng-click="removeMailFilterRule($index)" type="button">
<div class="md-icon-remove"><!-- delete --></div>
</md-button>
</md-item-content>
</md-item>
</md-list>
</div>
<md-button ng-click="addMailFilterRule($event)" type="button">
<div class="md-icon-add"><!-- create --></div>
</md-button>
</div>
<!-- <div id="splitter" class="dragHandle"></div> -->
<!-- ACTIONS -->
<div id="filterActionsContainer" class="container">
<var:string label:value="Perform these actions:"/><br/>
<div id="filterActions"><!-- empty --></div>
<div class="bottomToolbar"
><a const:id="actionAdd" class="bottomButton" href="#">
<span><img rsrc:src="add-icon.png" label:title="Add" />
</span></a
><a const:id="actionDelete" class="bottomButton" href="#">
<span><img rsrc:src="remove-icon.png" label:title="Delete" />
</span></a
></div>
<md-list>
<md-item ng-repeat="action in filter.actions">
<md-item-content>
<md-select ng-model="action.method">
<md-option ng-value="key" ng-repeat="(key, value) in methodLabels">{{ value }}</md-option>
</md-select>
<!-- FORWARD MESSAGE TO -->
<input type="text" ng-show="action.method == 'redirect'" ng-model="action.argument"/>
<!-- DISCARD -->
<!-- nada -->
<!-- KEEP -->
<!-- nada -->
<!-- SEND REJECT MESSAGE -->
<input type="text" ng-show="action.method == 'reject'" ng-model="action.argument"/>
<!-- FILE INTO -->
<md-select ng-show="action.method == 'fileinto'" ng-model="action.argument">
<md-option ng-value="item.path" ng-repeat="item in mailboxes">
{{ item.name }}
</md-option>
</md-select>
<!-- FLAG WITH -->
<md-select ng-show="action.method == 'addflag'" ng-model="action.argument" >
<md-option ng-value="key" ng-repeat="(key, value) in labels">{{ value[0] }}</md-option>
</md-select>
<!-- STOP -->
<!-- nada -->
<md-button ng-click="removeMailFilterAction($index)" type="button">
<div class="md-icon-remove"><!-- delete --></div>
</md-button>
</md-item-content>
</md-item>
</md-list>
<md-button ng-click="addMailFilterAction($event)" type="button">
<div class="md-icon-add"><!-- create --></div>
</md-button>
</div>
<div class="md-actions" layout="row">
<md-button type="button" ng-click="cancel()">Cancel</md-button>
<md-button type="button" class="md-primary" ng-click="save()">Save</md-button>
</div>
</form>
</md-content>
</md-dialog>
</var:component>
File diff suppressed because it is too large Load Diff
@@ -42,7 +42,7 @@
$q: $q,
$timeout: $timeout,
$log: $log,
$$resource: new Resource(Settings.baseURL, Settings.activeUser),
$$resource: new Resource(Settings.activeUser.folderURL + 'Mail', Settings.activeUser),
$Message: Message,
PRELOAD: PRELOAD
});
@@ -0,0 +1,106 @@
/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
(function() {
'use strict';
/**
* @name Preferences
* @constructor
*/
function Preferences() {
var _this = this;
this.defaults = {};
this.settings = {};
this.mailboxes = Preferences.$Mailbox.$find({ id: 0 });
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];
}));
data.SOGoMailLabelsColors = labels;
angular.extend(_this.defaults, data);
});
});
Preferences.$$resource.fetch("jsonSettings").then(function(data) {
Preferences.$timeout(function() {
angular.extend(_this.settings, data);
});
});
}
/**
* @memberof Preferences
* @desc The factory we'll use to register with Angular
* @returns the Preferences constructor
*/
Preferences.$factory = ['$q', '$timeout', '$log', 'sgSettings', 'sgResource', 'sgMailbox', function($q, $timeout, $log, Settings, Resource, Mailbox) {
angular.extend(Preferences, {
$q: $q,
$timeout: $timeout,
$log: $log,
$$resource: new Resource(Settings.activeUser.folderURL, Settings.activeUser),
activeUser: Settings.activeUser,
$Mailbox: Mailbox
});
return Preferences; // return constructor
}];
/* Factory registration in Angular module */
angular.module('SOGo.PreferencesUI')
.factory('sgPreferences', Preferences.$factory);
/**
* @function $save
* @memberof Preferences.prototype
* @desc Save the preferences to the server.
*/
Preferences.prototype.$save = function() {
var _this = this;
console.debug("save in model...");
return Preferences.$$resource.save("Preferences",
this.$omit(),
undefined)
.then(function(data) {
// Make a copy of the data for an eventual reset
//_this.$shadowData = _this.$omit(true);
return data;
});
};
/**
* @function $omit
* @memberof Preferences.prototype
* @desc Return a sanitized object used to send to the server.
* @param {Boolean} [deep] - make a deep copy if true
* @return an object literal copy of the Preferences instance
*/
Preferences.prototype.$omit = function(deep) {
var preferences = {};
angular.forEach(this, function(value, key) {
if (key == 'refs') {
preferences.refs = _.map(value, function(o) {
return o.$omit(deep);
});
}
else if (key != 'constructor' && key[0] != '$') {
if (deep)
preferences[key] = angular.copy(value);
else
preferences[key] = value;
}
});
return preferences;
};
})();
+250
View File
@@ -0,0 +1,250 @@
/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* JavaScript for SOGoPreferences */
(function() {
'use strict';
angular.module('SOGo.Common', []);
angular.module('SOGo.MailerUI', []);
angular.module('SOGo.PreferencesUI', ['ngSanitize', 'ui.router', 'SOGo.Common', 'SOGo.MailerUI', 'SOGo.UIDesktop', 'SOGo.UI'])
.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', '$mdDialog', 'sgPreferences', 'statePreferences', function($scope, $timeout, $mdDialog, Preferences, statePreferences) {
$scope.preferences = statePreferences;
$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);
$mdDialog.show({
controller: AccountDialogCtrl,
templateUrl: 'editAccount?account=new',
targetEvent: ev,
locals: { account: account }
});
};
$scope.editMailAccount = function(index) {
var account = $scope.preferences.defaults.AuxiliaryMailAccounts[index];
$mdDialog.show({
controller: AccountDialogCtrl,
templateUrl: 'editAccount?account=' + index,
targetEvent: null,
locals: { account: account }
}).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["foo_bar"] = ["foo bar", "#FFFF00"];
};
$scope.removeMailLabel = function(key) {
delete $scope.preferences.defaults.SOGoMailLabelsColors[key];
};
$scope.addMailFilter = function(ev) {
$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.addPreventInvitationsWhitelist = function() {
$scope.preferences.settings.Calendar.PreventInvitationsWhitelist.push("");
};
$scope.removePreventInvitationsWhitelist = function() {
$scope.preferences.settings.Calendar.PreventInvitationsWhitelist.pop();
};
$scope.save = function() {
console.debug("save");
$scope.preferences.$save();
};
$scope.changePassword = function() {
console.debug("change password");
};
}]);
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) {
$scope.filter.rules.push({});
}
$scope.removeMailFilterRule = function(index) {
$scope.filter.rules.splice(index, 1);
};
$scope.addMailFilterAction = function(event) {
$scope.filter.actions.push({});
}
$scope.removeMailFilterAction = function(index) {
$scope.filter.actions.splice(index, 1);
};
}
function AccountDialogCtrl($scope, $mdDialog, account) {
$scope.account = account;
$scope.cancel = function() {
$mdDialog.cancel();
};
$scope.save = function() {
$mdDialog.hide();
};
}
})();
@@ -0,0 +1,182 @@
@import "settings";
//$primary-color: #75B4BF;
//$topbar-link-bg-active: #75B4BF;
//$topbar-bg-color: $primary-color;
$module-color: #75B4BF;
$module-color: #C6C543;
$module-color: #6F5A73;
$module-secondary-color: #8EC588; // light green
$module-secondary-color: #3D792A; // green
$module-secondary-color: #B996BF;
$module-secondary-color: #B59BB9; // SOGo green
$module-light-color: #F7ECFF;
$topbar-bg-color: $module-color;
$topbar-link-bg-active-hover: scale-color($module-secondary-color, $lightness: -14%);
$topbar-link-bg-active: $module-secondary-color;
$topbar-link-bg-hover: scale-color($module-color, $lightness: -14%);
//$topbar-link-font-size: rem-calc(12);
//$off-canvas-link-text-size: rem-calc(12);
//$table-head-font-size: rem-calc(12);
//$table-row-font-size: rem-calc(12);
@import "foundation";
//@import "foundation/components/grid";
//@import "foundation/components/dropdown", "foundation/components/offcanvas", "foundation/components/top-bar";
//@import "toolbars";
@mixin off-canvas-list {
list-style-type: none;
padding:0;
margin:0;
display: table;
width: 100%;
li {
/*
+-----------------------------------------------+
+ li |
|+------+-----------------------------+--------+|
|| i | form | span ||
|+------+-----------------------------+--------+|
+-----------------------------------------------+
*/
display: table-row;
transition: background 300ms ease;
width: 100%;
label {
display: block;
padding: $off-canvas-label-padding;
color: $off-canvas-label-color;
text-transform: $off-canvas-label-text-transform;
font-size: $off-canvas-label-font-size;
font-weight: $off-canvas-label-font-weight;
background: $off-canvas-label-bg;
border-top: $off-canvas-label-border-top;
border-bottom: $off-canvas-label-border-bottom;
margin: $off-canvas-label-margin;
}
>* {
display: table-cell;
padding: $off-canvas-link-padding;
color: $off-canvas-link-color;
border-bottom: $off-canvas-link-border-bottom;
//vertical-align: middle;
}
.icon {
//vertical-align: middle; // causes glitch when selecting row
width: 2em;
}
form {
margin: 0;
padding-left: 0;
padding-right: 0;
* {
color: $off-canvas-link-color;
display: block;
width: 100%;
padding: 0;
//padding-left: $off-canvas-link-padding;
}
input {
border: 0;
color: #333 !important;
font-size: 1rem;
height: $off-canvas-link-padding/2+1rem;
margin: 0;
}
}
&:hover {
background: scale-color($tabbar-bg, $lightness: -30%);
}
&._selected {
background-color: #242424 !important;
border: 0 !important;
* {
color: #eee;
}
}
}
}
$total-columns: 13;
$column-gutter: 0;
#pageContent {
#mainMenu {
position: absolute;
overflow: auto;
overflow-x: hidden;
top: $topbar-height;
bottom: 0;
background-color: #333;
@include grid-column($columns:13); //, $collapse:true);
@media #{$medium-up} {
@include grid-column($columns:3);
}
ul {
margin: 0;
list-style-type: none;
li {
color: rgba(255, 255, 255, 0.7);
line-height: 50px;
padding-left: 10px;
&:hover, &:active {
background-color: #242424 !important;
color: white;
}
&._selected {
background-color: $module-color;
background-color: #fff;
}
i {
margin-right: 10px;
}
}
}
}
#container {
position: absolute;
top: $topbar-height;
background-color: #eeeeee;
bottom: 0;
left: 23%;
overflow: auto;
overflow-x: hidden;
border-left: $topbar-divider-border-bottom;
@include grid-column($columns:13);
@media #{$medium-up} {
@include grid-column($columns:10);
}
#viewer {
padding: 10px;
height: 100%;
#generalOptionsView, #calendarOptionsView, #addressbookOptionsView, #mailOptionsView {
height: inherit;
}
table {
width: 100%;
height: inherit;
margin: 0;
.td_1 {
text-align: right;
font-weight: bold;
width: 20%;
}
select, input {
margin: 0;
}
}
.submitButton {
margin: 0;
float: right;
border-radius: 3px;
}
}
}
}