mirror of
https://github.com/inverse-inc/sogo.git
synced 2026-07-08 09:55:09 +00:00
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:
committed by
Francis Lachapelle
parent
575676deb8
commit
5c3f0138f5
@@ -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"];
|
||||
|
||||
@@ -13,6 +13,7 @@ PreferencesUI_OBJC_FILES = \
|
||||
\
|
||||
UIxJSONPreferences.m \
|
||||
UIxPreferences.m \
|
||||
UIxAccountEditor.m \
|
||||
UIxFilterEditor.m \
|
||||
\
|
||||
UIxAdditionalPreferences.m
|
||||
|
||||
@@ -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,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,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,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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
})();
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user