Compare commits

..
Author SHA1 Message Date
Luc Charland 1dd4d870e0 Changed the keyname to EventsSortingState 2015-08-06 12:38:26 -04:00
196 changed files with 3129 additions and 103209 deletions

No files matched your search

+393 -13095
View File
File diff suppressed because it is too large. Load diff
-1
View File
@@ -7,7 +7,6 @@ Bug fixes
- Fixed several sync issues on environments with multiple users (Zentyal)
- Folders from other users will no longer appear on your Outlook (Zentyal)
- Use right auth in multidomain environments in contacts and calendar from Outlook (Zentyal)
- Session fix when SOGoEnableDomainBasedUID is enabled but logins are domain-less
2.3.1 (2015-07-23)
------------------
@@ -1493,9 +1493,8 @@ inRecurrenceExceptionsForEvent: (iCalEvent *) theEvent
// the database. We do this ONLY when using SOGo from the
// Web interface or over ActiveSync.
// Over DAV, it'll be handled directly in PUTAction:
if (![context request] ||
[[context request] handledByDefaultHandler] ||
[[[context request] requestHandlerKey] isEqualToString: @"Microsoft-Server-ActiveSync"])
if (![context request] || [[context request] handledByDefaultHandler]
|| [[[context request] requestHandlerKey] isEqualToString: @"Microsoft-Server-ActiveSync"])
{
// If an alarm was specified, let's use it. This would happen if an attendee accepts/declines/etc. an
// event invitation and also sets an alarm along the way. This would happen ONLY from the web interface.
@@ -84,30 +84,17 @@
*/
- (NSDictionary *) attributesInContext: (WOContext *) context
{
NSArray *allEvents, *rules;
NSArray *rules;
NSCalendarDate *untilDate;
NSMutableDictionary *data, *repeat;
NSString *frequency;
NSTimeZone *timeZone;
SOGoUserDefaults *ud;
iCalEvent *masterComponent;
iCalRecurrenceRule *rule;
data = [NSMutableDictionary dictionaryWithDictionary: [super attributesInContext: context]];
if ([self recurrenceId])
{
// If the component is an occurrence of a recurrent component,
// consider the recurrence rules of the master component.
allEvents = [[self parent] events];
masterComponent = [allEvents objectAtIndex: 0];
rules = [masterComponent recurrenceRules];
}
else
{
rules = [self recurrenceRules];
}
rules = [self recurrenceRules];
if ([rules count] > 0)
{
rule = [rules objectAtIndex: 0];
+1 -5
View File
@@ -1,6 +1,6 @@
/* NGVCard+SOGo.h - this file is part of SOGo
*
* Copyright (C) 2009-2015 Inverse inc.
* Copyright (C) 2009-2014 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
@@ -31,10 +31,6 @@
- (CardElement *) elementWithTag: (NSString *) elementTag
ofType: (NSString *) type;
- (void) addElementWithTag: (NSString *) elementTag
ofType: (NSString *) type
withValue: (id) value;
- (void) updateFromLDIFRecord: (NSDictionary *) ldifRecord;
- (NSMutableDictionary *) asLDIFRecord;
+2 -2
View File
@@ -188,8 +188,8 @@ convention:
}
- (void) addElementWithTag: (NSString *) elementTag
ofType: (NSString *) type
withValue: (id) value
ofType: (NSString *) type
withValue: (id) value
{
NSArray *allValues;
NSEnumerator *list;
+3 -6
View File
@@ -1,5 +1,6 @@
/*
Copyright (C) 2006-2015 Inverse inc.
Copyright (C) 2006-2014 Inverse inc.
Copyright (C) 2004-2005 SKYRIX Software AG
This file is part of SOGo.
@@ -31,13 +32,9 @@
@class NSString;
@interface SOGoContactGCSFolder : SOGoGCSFolder <SOGoContactFolder>
{
NSString *baseCardDAVURL, *basePublicCardDAVURL;
}
- (void) fixupContactRecord: (NSMutableDictionary *) contactRecord;
- (NSDictionary *) lookupContactWithName: (NSString *) aName;
- (NSString *) cardDavURL;
- (NSString *) publicCardDavURL;
@end
+2 -63
View File
@@ -1,5 +1,6 @@
/*
Copyright (C) 2006-2013-2015 Inverse inc.
Copyright (C) 2006-2013 Inverse inc.
Copyright (C) 2004-2005 SKYRIX Software AG
This file is part of SOGo.
@@ -66,24 +67,6 @@ static NSArray *folderListingFields = nil;
@"c_component", nil];
}
- (id) init
{
if ((self = [super init]))
{
baseCardDAVURL = nil;
basePublicCardDAVURL = nil;
}
return self;
}
- (void) dealloc
{
[baseCardDAVURL release];
[basePublicCardDAVURL release];
[super dealloc];
}
- (Class) objectClassForContent: (NSString *) content
{
CardGroup *cardEntry;
@@ -453,48 +436,4 @@ static NSArray *folderListingFields = nil;
return [NSString stringWithFormat: @"%@:%@", nsRep, nodeName];
}
- (NSString *) _baseCardDAVURL
{
NSString *davURL;
if (!baseCardDAVURL)
{
davURL = [[self realDavURL] absoluteString];
if ([davURL hasSuffix: @"/"])
baseCardDAVURL = [davURL substringToIndex: [davURL length] - 1];
else
baseCardDAVURL = davURL;
[baseCardDAVURL retain];
}
return baseCardDAVURL;
}
- (NSString *) cardDavURL
{
return [NSString stringWithFormat: @"%@/", [self _baseCardDAVURL]];
}
- (NSString *) _basePublicCardDAVURL
{
NSString *davURL;
if (!basePublicCardDAVURL)
{
davURL = [[self publicDavURL] absoluteString];
if ([davURL hasSuffix: @"/"])
basePublicCardDAVURL = [davURL substringToIndex: [davURL length] - 1];
else
basePublicCardDAVURL = davURL;
[basePublicCardDAVURL retain];
}
return basePublicCardDAVURL;
}
- (NSString *) publicCardDavURL
{
return [NSString stringWithFormat: @"%@/", [self _basePublicCardDAVURL]];
}
@end /* SOGoContactGCSFolder */
+3 -1
View File
@@ -1,6 +1,8 @@
/* NSArray+Utilities.h - this file is part of SOGo
*
* Copyright (C) 2006-2015 Inverse inc.
* Copyright (C) 2006 Inverse inc.
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
*
* 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
+3 -1
View File
@@ -1,6 +1,8 @@
/* NSArray+Utilities.m - this file is part of SOGo
*
* Copyright (C) 2006-2015 Inverse inc.
* Copyright (C) 2006-2011 Inverse inc.
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
*
* 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
+3 -1
View File
@@ -1,6 +1,8 @@
/* NSObject+Utilities.h - this file is part of SOGo
*
* Copyright (C) 2007-2015 Inverse inc.
* Copyright (C) 2007 Inverse inc.
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
*
* 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
+3 -1
View File
@@ -1,6 +1,8 @@
/* NSObject+Utilities.m - this file is part of SOGo
*
* Copyright (C) 2007-2015 Inverse inc.
* Copyright (C) 2007 Inverse inc.
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
*
* 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 -4
View File
@@ -778,10 +778,7 @@ static Class NSNullK;
NSRange r;
r = [theUID rangeOfString: [NSString stringWithFormat: @"@%@", theDomain]];
// We check if the range is ok here since we could be using DomainLessLogin
if (r.location != NSNotFound)
theUID = [theUID substringToIndex: r.location];
theUID = [theUID substringToIndex: r.location];
}
sogoSources = [[self authenticationSourceIDsInDomain: theDomain] objectEnumerator];
+1 -5
View File
@@ -70,11 +70,7 @@ class Carddav:
if not self.cards:
url = "/SOGo/so/%s/Contacts/personal/view" % (self.login)
content = self._get(url)
#print "\nCONTENT:", content
if 'cards' in content:
self.cards = content['cards']
else:
self.cards = []
self.cards = content['cards']
return self.cards
def get_cards(self, pattern):
+4 -4
View File
@@ -89,9 +89,9 @@ class preferences:
get = HTTPPreferencesGET(url)
get.cookie = self.cookie
self.client.execute(get)
if DEBUG: print "DEBUG (url):", url
if DEBUG: print "DEBUG (status):", get.response["status"]
if DEBUG: print "DEBUG (body):", get.response['body']
if DEBUG: print "LUC (url):", url
if DEBUG: print "LUC (status):", get.response["status"]
if DEBUG: print "LUC (body):", get.response['body']
content = simplejson.loads(get.response['body'])
result = None
try:
@@ -117,7 +117,7 @@ class preferences:
# Get the right sub-dict and change the key/value
subdict = self.find_key(self.preferences, preference)
if not subdict:
raise AttributeError("ERROR(nosubdict): looking for %s in: %s" %(preference, str(self.preferences)))
print "LUC(nosubdict):", preference, self.preferences
subdict[preference] = value
def set(self, preference, value=None):
-24
View File
@@ -85,13 +85,6 @@ class JsonDavPhoneTests(unittest.TestCase):
self.allphones = list(self.newphone)
self.allphones.extend(self.newphones_difftype)
self.allphones.extend(self.newphones_sametype)
#- In case there are no cards for this user
try:
self._get_card()
except IndexError:
path = 'Contacts/personal'
(card, path, gid) = self._create_new_card(path)
self._save_card(card)
def tearDown(self):
self._connect_as_user()
@@ -109,23 +102,6 @@ class JsonDavPhoneTests(unittest.TestCase):
def _connect_as_user(self, newuser=username, newpassword=password):
self.dv = carddav.Carddav(newuser, newpassword)
def _create_new_card(self, path):
gid = self.dv.newguid(path)
card = {'c_categories': None,
'c_cn': 'John Doe',
'c_component': 'vcard',
'c_givenname': 'John Doe',
'c_mail': 'johndoe@nothere.com',
'c_name': gid,
'c_o': '',
'c_screenname': '',
'c_sn': '',
'c_telephonenumber': '123.456.7890',
'emails': [{'type': 'pref', 'value': 'johndoe@nothere.com'}],
'phones': [{'type': 'home', 'value': '111.222.3333'}],
'id': gid}
return (card, path, gid)
def _get_card(self, name="John Doe"):
tmp_card = self.dv.get_cards(name)[0]
self.card = self.dv.get_card(tmp_card['c_name'])
@@ -28,14 +28,12 @@ class preventInvitationsTest(unittest.TestCase):
self.caldav = CalDAVSchedulingTest(self)
cal = self.prefs.get("Calendar")
if "PreventInvitationsWhitelist" not in cal:
#print "LUC (cal):", cal
cal["PreventInvitationsWhitelist"] = None
self.prefs.set("PreventInvitationsWhitelist", None)
if "PreventInvitations" not in cal:
cal["PreventInvitations"] = 0
self.prefs.set("PreventInvitations", 0)
def tearDown(self):
#self.prefs.set("autoReplyText", "")
self.prefs.set("autoReplyText", "")
self.prefs.set('PreventInvitations', 0)
self.prefs.set("PreventInvitationsWhitelist", None)
#- Manual Cleanup, not called because classs is not derived from unittest
+6 -4
View File
@@ -21,8 +21,8 @@ class UIPostsTests(unittest.TestCase):
self.cookie = sogoLogin.getAuthCookie(hostname, port, username, password)
def _urlPostData(self, client, url, data, exp_status=200):
post = webdavlib.HTTPPOST(url, simplejson.dumps(data))
post.content_type = "application/json"
post = webdavlib.HTTPPOST(url, data)
post.content_type = "application/x-www-form-urlencoded"
post.cookie = self.cookie
client.execute(post)
@@ -43,14 +43,16 @@ class UIPostsTests(unittest.TestCase):
""" Add Web Calendar """
ret=True
data = {"url":"%s" % webCalendarURL}
data = "url=%s" % webCalendarURL
calendarBaseURL="/SOGo/so/%s/Calendar" % username
addWebCalendarURL = "%s/addWebCalendar" % calendarBaseURL
response = self._urlPostData(self.client, addWebCalendarURL, data)
respJSON = simplejson.loads(response['body'])
calID = respJSON['id']
folderID = respJSON['folderID']
#sogo1:Calendar/C07-5006F300-1-370E2480
(_, calID) = folderID.split('/', 1)
self.assertNotEqual(calID, None)
# reload the cal
+8 -10
View File
@@ -408,17 +408,16 @@
- (id <WOActionResults>) copyAction
{
WORequest *request;
id <WOActionResults> response;
NSString *destinationFolderId;
NSArray *contactsId;
NSDictionary *data;
NSException *ex;
data = [[[context request] contentAsString] objectFromJSONString];
contactsId = [data objectForKey: @"uids"];
destinationFolderId = [data objectForKey: @"folder"];
request = [context request];
if (destinationFolderId && [contactsId count])
if ((destinationFolderId = [request formValueForKey: @"folder"]) &&
(contactsId = [request formValuesForKey: @"uid"]))
ex = [self _moveContacts: contactsId
toFolder: destinationFolderId
andKeepCopy: YES];
@@ -437,17 +436,16 @@
- (id <WOActionResults>) moveAction
{
WORequest *request;
id <WOActionResults> response;
NSString *destinationFolderId;
NSDictionary *data;
NSArray *contactsId;
NSException *ex;
data = [[[context request] contentAsString] objectFromJSONString];
contactsId = [data objectForKey: @"uids"];
destinationFolderId = [data objectForKey: @"folder"];
request = [context request];
if (destinationFolderId && [contactsId count])
if ((destinationFolderId = [request formValueForKey: @"folder"])
&& (contactsId = [request formValuesForKey: @"uid"]))
ex = [self _moveContacts: contactsId
toFolder: destinationFolderId
andKeepCopy: NO];
+34 -6
View File
@@ -440,6 +440,40 @@
return ([[self productCSSURL] length] > 0);
}
- (BOOL) _moduleIs: (NSString *) moduleName
{
NSString *frameworkName;
frameworkName = [[context page] frameworkName];
return [frameworkName isEqualToString: moduleName];
}
- (BOOL) isCalendar
{
return [self _moduleIs: @"SchedulerUI"];
}
- (BOOL) isContacts
{
return [self _moduleIs: @"ContactsUI"];
}
- (BOOL) isMail
{
return [self _moduleIs: @"MailerUI"];
}
- (BOOL) isPreferences
{
return [self _moduleIs: @"PreferencesUI"];
}
- (BOOL) isAdministration
{
return [self _moduleIs: @"AdministrationUI"];
}
- (void) setToolbar: (NSString *) newToolbar
{
ASSIGN (toolbar, newToolbar);
@@ -475,12 +509,6 @@
return [[context activeUser] cn];
}
- (NSString *) userEmail
{
return [[context activeUser] systemEmail];
}
- (BOOL) canLogoff
{
BOOL canLogoff;
@@ -43,12 +43,6 @@
"Copy To" = "Copy To";
"Add to:" = "Add to:";
/* Number of selected contacts in list */
"selected" = "selected";
/* Empty right pane */
"No contact selected" = "No contact selected";
/* Tooltips */
"Create a new address book card" = "Create a new address book card";
+6 -11
View File
@@ -367,8 +367,6 @@ static Class SOGoContactGCSEntryK = Nil;
day = [date dayOfMonth];
[card setBday: [NSString stringWithFormat: @"%.4d%.2d%.2d", year, month, day]];
}
else
[card setBday: nil];
if ([[attributes objectForKey: @"addresses"] isKindOfClass: [NSArray class]])
{
@@ -432,9 +430,8 @@ static Class SOGoContactGCSEntryK = Nil;
{
if ([attrs isKindOfClass: [NSDictionary class]])
{
[card addElementWithTag: @"tel"
ofType: [attrs objectForKey: @"type"]
withValue: [attrs objectForKey: @"value"]];
element = [card elementWithTag: @"tel" ofType: [attrs objectForKey: @"type"]];
[element setSingleValue: [attrs objectForKey: @"value"] forKey: @""];
}
}
}
@@ -451,9 +448,8 @@ static Class SOGoContactGCSEntryK = Nil;
{
if ([o isKindOfClass: [NSDictionary class]])
{
[card addElementWithTag: @"email"
ofType: [o objectForKey: @"type"]
withValue: [o objectForKey: @"value"]];
element = [card elementWithTag: @"email" ofType: [o objectForKey: @"type"]];
[element setSingleValue: [o objectForKey: @"value"] forKey: @""];
}
}
}
@@ -470,9 +466,8 @@ static Class SOGoContactGCSEntryK = Nil;
{
if ([attrs isKindOfClass: [NSDictionary class]])
{
[card addElementWithTag: @"url"
ofType: [attrs objectForKey: @"type"]
withValue: [attrs objectForKey: @"value"]];
element = [card elementWithTag: @"url" ofType: [attrs objectForKey: @"type"]];
[element setSingleValue: [attrs objectForKey: @"value"] forKey: @""];
}
}
}
+13 -7
View File
@@ -112,11 +112,15 @@
request = [context request];
rc = [NSMutableDictionary dictionary];
data = [[[[[request httpRequest] body] parts] lastObject] body];
fileContent = [[NSString alloc] initWithData: (NSData *) data
encoding: NSUTF8StringEncoding];
[fileContent autorelease];
data = [request formValueForKey: @"contactsFile"];
if ([data respondsToSelector: @selector(isEqualToString:)])
fileContent = (NSString *) data;
else
{
fileContent = [[NSString alloc] initWithData: (NSData *) data
encoding: NSUTF8StringEncoding];
[fileContent autorelease];
}
if (fileContent && [fileContent length])
{
@@ -128,10 +132,12 @@
imported = 0;
}
[rc setObject: [NSNumber numberWithInt: imported] forKey: @"imported"];
[rc setObject: [NSNumber numberWithInt: imported]
forKey: @"imported"];
response = [self responseWithStatus: 200];
[response setHeader: @"text/html" forKey: @"content-type"];
[response setHeader: @"text/html"
forKey: @"content-type"];
[(WOResponse*)response appendContentString: [rc jsonRepresentation]];
return response;
@@ -20,6 +20,14 @@
#import <SOGoUI/UIxComponent.h>
@class NSString;
@class SOGoContactGCSFolder;
@interface UIxContactFolderLinksTemplate : UIxComponent
{
SOGoContactGCSFolder *addressBook;
NSString *baseCardDAVURL, *basePublicCardDAVURL;
}
@end
@@ -24,6 +24,69 @@
@implementation UIxContactFolderLinksTemplate
- (id) init
{
if ((self = [super init]))
{
addressBook = [self clientObject];
baseCardDAVURL = nil;
basePublicCardDAVURL = nil;
}
return self;
}
- (void) dealloc
{
[baseCardDAVURL release];
[basePublicCardDAVURL release];
[super dealloc];
}
- (NSString *) _baseCardDAVURL
{
NSString *davURL;
if (!baseCardDAVURL)
{
davURL = [[addressBook realDavURL] absoluteString];
if ([davURL hasSuffix: @"/"])
baseCardDAVURL = [davURL substringToIndex: [davURL length] - 1];
else
baseCardDAVURL = davURL;
[baseCardDAVURL retain];
}
return baseCardDAVURL;
}
- (NSString *) cardDavURL
{
return [NSString stringWithFormat: @"%@/", [self _baseCardDAVURL]];
}
- (NSString *) _basePublicCardDAVURL
{
NSString *davURL;
if (!basePublicCardDAVURL)
{
davURL = [[addressBook publicDavURL] absoluteString];
if ([davURL hasSuffix: @"/"])
basePublicCardDAVURL = [davURL substringToIndex: [davURL length] - 1];
else
basePublicCardDAVURL = davURL;
[basePublicCardDAVURL retain];
}
return basePublicCardDAVURL;
}
- (NSString *) publicCardDavURL
{
return [NSString stringWithFormat: @"%@/", [self _basePublicCardDAVURL]];
}
- (BOOL) isPublicAccessEnabled
{
// NOTE: This method is the same found in Common/UIxAclEditor.m
+11 -43
View File
@@ -275,70 +275,32 @@ Class SOGoContactSourceFolderK, SOGoGCSFolderK;
return [[self queryParameterForKey: @"popup"] boolValue];
}
- (BOOL) isPublicAccessEnabled
{
// NOTE: This method is the same found in Common/UIxAclEditor.m
return [[SOGoSystemDefaults sharedSystemDefaults] enablePublicAccess];
}
- (NSString *) contactFolders
{
SOGoContactFolders *folderContainer;
NSMutableDictionary *urls, *acls;
NSArray *folders;
NSMutableArray *foldersAttrs;
NSString *userLogin, *owner;
NSArray *folders, *allACLs;
NSDictionary *folderAttrs;
id currentFolder;
BOOL objectCreator, objectEditor, objectEraser;
int max, i;
userLogin = [[context activeUser] login];
folderContainer = [self clientObject];
folders = [folderContainer subFolders];
// return [folderContainer subFolders];
folders = [folderContainer subFolders];
max = [folders count];
foldersAttrs = [NSMutableArray arrayWithCapacity: max];
urls = nil;
for (i = 0; i < max; i++)
{
currentFolder = [folders objectAtIndex: i];
owner = [currentFolder ownerInContext: context];
// We extract URLs for this address book
if ([currentFolder respondsToSelector: @selector(cardDavURL)])
{
urls = [NSMutableDictionary dictionaryWithObjectsAndKeys:
[currentFolder cardDavURL], @"cardDavURL",
nil];
if ([self isPublicAccessEnabled])
{
[urls setObject: [currentFolder publicCardDavURL] forKey: @"publicCardDavURL"];
}
}
// We extract ACLs for this address book
allACLs = ([owner isEqualToString: userLogin] ? nil : [currentFolder aclsForUser: userLogin]);
objectCreator = ([owner isEqualToString: userLogin] || [allACLs containsObject: SOGoRole_ObjectCreator]);
objectEditor = ([owner isEqualToString: userLogin] || [allACLs containsObject: SOGoRole_ObjectEditor]);
objectEraser = ([owner isEqualToString: userLogin] || [allACLs containsObject: SOGoRole_ObjectEraser]);
acls = [NSDictionary dictionaryWithObjectsAndKeys: [NSNumber numberWithBool: objectCreator], @"objectCreator",
[NSNumber numberWithBool: objectEditor], @"objectEditor",
[NSNumber numberWithBool: objectEraser], @"objectEraser", nil];
// NOTE: keep urls as the last key/value here, to avoid chopping the dictionary
// if it is not a GCS folder
folderAttrs = [NSDictionary dictionaryWithObjectsAndKeys:
[NSString stringWithFormat: @"%@", [currentFolder nameInContainer]], @"id",
[currentFolder displayName], @"name",
owner, @"owner",
[currentFolder ownerInContext: context], @"owner",
[NSNumber numberWithBool: [currentFolder isKindOfClass: SOGoGCSFolderK]], @"isEditable",
[NSNumber numberWithBool: [currentFolder isKindOfClass: SOGoContactSourceFolderK]
&& ![currentFolder isPersonalSource]], @"isRemote",
acls, @"acls",
urls, @"urls",
nil];
[foldersAttrs addObject: folderAttrs];
}
@@ -457,6 +419,12 @@ Class SOGoContactSourceFolderK, SOGoGCSFolderK;
return [super defaultAction];
}
- (BOOL) isPublicAccessEnabled
{
// NOTE: This method is the same found in Common/UIxAclEditor.m
return [[SOGoSystemDefaults sharedSystemDefaults] enablePublicAccess];
}
@end
@interface UIxContactViewTemplate : UIxComponent
+4 -3
View File
@@ -838,10 +838,11 @@
o = [card birthday];
if (o)
{
[data setObject: [NSNumber numberWithInt: [o timeIntervalSince1970]]
forKey: @"birthday"];
NSNumber *time = [NSNumber numberWithInt: [o timeIntervalSince1970]];
[data setObject: time forKey: @"birthday"];
}
// o = [card source];
// if (o) [data setObject: o forKey: @"source"];
o = [card tz];
if (o) [data setObject: o forKey: @"tz"];
+1 -31
View File
@@ -1,5 +1,5 @@
/*
Copyright (C) 2006-2015 Inverse inc.
Copyright (C) 2006-2014 Inverse inc.
This file is part of SOGo.
@@ -39,9 +39,6 @@
#import <Contacts/SOGoContactFolder.h>
#import <Contacts/SOGoContactFolders.h>
#import <SOGo/SOGoUser.h>
#import <SOGo/SOGoUserSettings.h>
#import <NGCards/NGVCard.h>
#import <NGCards/NGVList.h>
#import <SoObjects/Contacts/SOGoContactGCSEntry.h>
@@ -88,31 +85,6 @@
return s;
}
- (void) saveSortValue
{
NSMutableDictionary *contactSettings;
NSString *ascending, *sort;
SOGoUserSettings *us;
sort = [[context request] formValueForKey: @"sort"];
ascending = [[context request] formValueForKey: @"asc"];
if ([sort length])
{
us = [[context activeUser] userSettings];
contactSettings = [us objectForKey: @"Contact"];
// Must create if it doesn't exist
if (!contactSettings)
{
contactSettings = [NSMutableDictionary dictionary];
[us setObject: contactSettings forKey: @"Contact"];
}
[contactSettings setObject: [NSArray arrayWithObjects: [sort lowercaseString], [NSString stringWithFormat: @"%d", [ascending intValue]], nil]
forKey: @"SortingState"];
[us synchronize];
}
}
- (NSArray *) contactInfos
{
id <SOGoContactFolder> folder;
@@ -125,8 +97,6 @@
WORequest *rq;
unsigned int i;
[self saveSortValue];
if (!contactInfos)
{
folder = [self clientObject];
+3 -1
View File
@@ -1,6 +1,8 @@
/* UIxMailPartTextViewer.h - this file is part of $PROJECT_NAME_HERE$
*
* Copyright (C) 2006-2015 Inverse inc.
* Copyright (C) 2006 Inverse inc.
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
*
* 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
+20 -19
View File
@@ -1,22 +1,23 @@
/* UIxMailPartTextViewer.m - this file is part of $PROJECT_NAME_HERE$
*
* Copyright (C) 2006-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.
*/
/*
Copyright (C) 2004-2005 SKYRIX Software AG
This file is part of OpenGroupware.org.
OGo is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by the
Free Software Foundation; either version 2, or (at your option) any
later version.
OGo 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 Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public
License along with OGo; see the file COPYING. If not, write to the
Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA.
*/
/*
UIxMailPartTextViewer
@@ -65,9 +65,6 @@
"Account: " = "Account: ";
"Shared Account: " = "Shared Account: ";
/* Empty right pane */
"No message selected" = "No message selected";
/* acls */
"Access rights to" = "Access rights to";
"For user" = "For user";
+7 -7
View File
@@ -92,7 +92,7 @@
}
else
{
errorFormat = [self labelForKey: @"The folder with name \"%@\" could not be created." inContext: context];
errorFormat = [self labelForKey: @"The folder with name \"%@\" could not be created."];
jsonResponse = [NSDictionary dictionaryWithObject: [NSString stringWithFormat: errorFormat, folderName]
forKey: @"error"];
response = [self responseWithStatus: 500
@@ -101,7 +101,7 @@
}
else
{
jsonResponse = [NSDictionary dictionaryWithObject: [self labelForKey: @"Missing 'name' parameter." inContext: context]
jsonResponse = [NSDictionary dictionaryWithObject: [self labelForKey: @"Missing 'name' parameter."]
forKey: @"error"];
response = [self responseWithStatus: 500
andJSONRepresentation: jsonResponse];
@@ -149,7 +149,7 @@
if (!newFolderName || [newFolderName length] == 0)
{
message = [NSDictionary dictionaryWithObject: [self labelForKey: @"Missing name parameter" inContext: context]
message = [NSDictionary dictionaryWithObject: [self labelForKey: @"Missing name parameter"]
forKey: @"error"];
response = [self responseWithStatus: 500
andString: [message jsonRepresentation]];
@@ -160,7 +160,7 @@
error = [co renameTo: newFolderName];
if (error)
{
message = [NSDictionary dictionaryWithObject: [self labelForKey: @"Unable to rename folder." inContext: context]
message = [NSDictionary dictionaryWithObject: [self labelForKey: @"Unable to rename folder."]
forKey: @"error"];
response = [self responseWithStatus: 500
andString: [message jsonRepresentation]];
@@ -251,7 +251,7 @@
error = [connection moveMailboxAtURL: srcURL toURL: destURL];
if (error)
{
jsonResponse = [NSDictionary dictionaryWithObject: [self labelForKey: @"Unable to move folder." inContext: context]
jsonResponse = [NSDictionary dictionaryWithObject: [self labelForKey: @"Unable to move folder."]
forKey: @"error"];
response = [self responseWithStatus: 500
andString: [jsonResponse jsonRepresentation]];
@@ -283,7 +283,7 @@
}
else
{
jsonResponse = [NSDictionary dictionaryWithObject: [self labelForKey: @"Unable to move folder." inContext: context]
jsonResponse = [NSDictionary dictionaryWithObject: [self labelForKey: @"Unable to move folder."]
forKey: @"error"];
response = [self responseWithStatus: 500
andString: [jsonResponse jsonRepresentation]];
@@ -374,7 +374,7 @@
{
uids = [value componentsSeparatedByString: @","];
response = [co archiveUIDs: uids
inArchiveNamed: [self labelForKey: @"Saved Messages.zip" inContext: context]
inArchiveNamed: [self labelForKey: @"Saved Messages.zip"]
inContext: context];
if (!response)
response = [self responseWith204];
+13 -18
View File
@@ -55,7 +55,6 @@
#import <Mailer/SOGoSentFolder.h>
#import <SOGo/NSArray+Utilities.h>
#import <SOGo/NSDictionary+Utilities.h>
#import <SOGo/NSObject+Utilities.h>
#import <SOGo/NSString+Utilities.h>
#import <SOGo/SOGoDateFormatter.h>
#import <SOGo/SOGoUser.h>
@@ -132,7 +131,7 @@
else if ([now dayOfCommonEra] - [messageDate dayOfCommonEra] == 1)
{
// Yesterday
return [self labelForKey: @"Yesterday" inContext: context];
return [self labelForKey: @"Yesterday"];
}
else if ([now dayOfCommonEra] - [messageDate dayOfCommonEra] < 7)
{
@@ -191,10 +190,10 @@
s = [[s substringFromIndex: r.location+1]
stringByTrimmingCharactersInSet: [NSCharacterSet whitespaceAndNewlineCharacterSet]];
if ([s hasPrefix: @"1"]) result = [self labelForKey: @"highest" inContext: context];
else if ([s hasPrefix: @"2"]) result = [self labelForKey: @"high" inContext: context];
else if ([s hasPrefix: @"4"]) result = [self labelForKey: @"low" inContext: context];
else if ([s hasPrefix: @"5"]) result = [self labelForKey: @"lowest" inContext: context];
if ([s hasPrefix: @"1"]) result = [self labelForKey: @"highest"];
else if ([s hasPrefix: @"2"]) result = [self labelForKey: @"high"];
else if ([s hasPrefix: @"4"]) result = [self labelForKey: @"low"];
else if ([s hasPrefix: @"5"]) result = [self labelForKey: @"lowest"];
}
}
}
@@ -243,7 +242,7 @@
{
NSString *s;
s = [self labelForKey:@"View Mail Folder" inContext: context];
s = [self labelForKey:@"View Mail Folder"];
s = [s stringByAppendingString:@": "];
s = [s stringByAppendingString:[self objectTitle]];
return s;
@@ -623,12 +622,11 @@
- (NSDictionary *) getUIDsInFolder: (SOGoMailFolder *) folder
withHeaders: (BOOL) includeHeaders
{
NSArray *uids, *threadedUids, *headers;
NSMutableDictionary *data;
NSArray *uids, *threadedUids, *headers;
NSRange r;
SOGoMailAccount *account;
id quota;
NSRange r;
int count;
data = [NSMutableDictionary dictionary];
@@ -646,14 +644,10 @@
if (includeHeaders)
{
// Also retrieve the first headers, up to 'headersPrefetchMaxSize'
NSArray *a;
a = [uids flattenedArray];
count = [a count];
if (count > headersPrefetchMaxSize)
count = headersPrefetchMaxSize;
count = [[uids flattenedArray] count];
if (count > headersPrefetchMaxSize) count = headersPrefetchMaxSize;
r = NSMakeRange(0, count);
headers = [self getHeadersForUIDs: [a subarrayWithRange: r]
headers = [self getHeadersForUIDs: [[uids flattenedArray] subarrayWithRange: r]
inFolder: folder];
[data setObject: headers forKey: @"headers"];
@@ -750,6 +744,7 @@
noHeaders = [[[requestContent objectForKey: @"sortingAttributes"] objectForKey:@"noHeaders"] boolValue];
data = [self getUIDsInFolder: folder
withHeaders: !noHeaders];
[response appendContentString: [data jsonRepresentation]];
return response;
@@ -883,7 +878,7 @@
data = [NSDictionary dictionaryWithObjectsAndKeys:
@"No UID specified", @"error", nil];
return [self responseWithStatus: 404 /* Not Found */
andString: [data jsonRepresentation]];
andString: [data jsonRepresentation]];
}
uids = [data objectForKey: @"uids"];
-12
View File
@@ -118,18 +118,6 @@
return [accounts jsonRepresentation];
}
- (WOResponse *) mailAccountsAction
{
WOResponse *response;
NSString *s;
s = [self mailAccounts];
response = [self responseWithStatus: 200
andString: s];
return response;
}
- (NSString *) userNames
{
NSArray *accounts, *userNames;
-5
View File
@@ -342,11 +342,6 @@
actionClass = "UIxMailMainFrame";
actionName = "unseenCount";
};
mailAccounts = {
protectedBy = "View";
actionClass = "UIxMailMainFrame";
actionName = "mailAccounts";
};
// viewerTemplate = {
// protectedBy = "View";
// pageName = "UIxMailViewTemplate";
@@ -9,7 +9,6 @@
"Connect" = "Connect";
"Authentication Failed" = "Authentication Failed";
"Wrong username or password." = "Wrong username or password.";
"cookiesNotEnabled" = "You cannot login because your browser's cookies are disabled. Please enable cookies in your browser's settings and try again.";
+6 -7
View File
@@ -183,6 +183,7 @@
SOGoWebAuthenticator *auth;
SOGoAppointmentFolders *calendars;
SOGoUserDefaults *ud;
SOGoSystemDefaults *sd;
SOGoUser *loggedInUser;
NSDictionary *params;
NSString *username, *password, *language, *domain, *remoteHost;
@@ -225,15 +226,13 @@
response = [self responseWithStatus: 200
andJSONRepresentation: json];
// We get the proper username for cookie creation. If we are using a multidomain
// environment with SOGoEnableDomainBasedUID, we could have to append the domain
// to the username. Also when SOGoEnableDomainBasedUID is enabled, we could be in
// the DomainLessLogin situation, so we would NOT add the domain. -getUIDForEmail
// has all the logic for this, so lets use it.
if ([domain isNotNull])
{
username = [[SOGoUserManager sharedUserManager] getUIDForEmail: username];
sd = [SOGoSystemDefaults sharedSystemDefaults];
if ([sd enableDomainBasedUID] &&
[username rangeOfString: @"@"].location == NSNotFound)
username = [NSString stringWithFormat: @"%@@%@", username, domain];
}
authCookie = [auth cookieWithUsername: username
@@ -1,7 +1,6 @@
/* toolbar */
"Save and Close" = "Save and Close";
"Close" = "Close";
"Preferences saved" = "Preferences saved";
/* tabs */
"General" = "General";
+20 -35
View File
@@ -61,8 +61,7 @@ static SoProduct *preferencesProduct = nil;
SOGoUserDefaults *defaults;
NSMutableArray *accounts;
NSArray *categoryLabels;
NSDictionary *locale;
if (!preferencesProduct)
{
preferencesProduct = [[SoProduct alloc] initWithBundle:
@@ -79,7 +78,7 @@ static SoProduct *preferencesProduct = nil;
if (![[defaults source] objectForKey: @"SOGoTimeZone"])
[[defaults source] setObject: [defaults timeZoneName] forKey: @"SOGoTimeZone"];
if (![[defaults source] objectForKey: @"SOGoShortDateFormat"])
[[defaults source] setObject: [defaults shortDateFormat] forKey: @"SOGoShortDateFormat"];
@@ -91,7 +90,7 @@ static SoProduct *preferencesProduct = nil;
if (![[defaults source] objectForKey: @"SOGoLoginModule"])
[[defaults source] setObject: [defaults loginModule] forKey: @"SOGoLoginModule"];
if (![[defaults source] objectForKey: @"SOGoRefreshViewCheck"])
[[defaults source] setObject: [defaults refreshViewCheck] forKey: @"SOGoRefreshViewCheck"];
@@ -100,13 +99,13 @@ static SoProduct *preferencesProduct = nil;
//
if (![[defaults source] objectForKey: @"SOGoFirstDayOfWeek"])
[[defaults source] setObject: [NSNumber numberWithInt: [defaults firstDayOfWeek]] forKey: @"SOGoFirstDayOfWeek"];
if (![[defaults source] objectForKey: @"SOGoDayStartTime"])
[[defaults source] setObject: [NSString stringWithFormat: @"%02d:00", [defaults dayStartHour]] forKey: @"SOGoDayStartTime"];
if (![[defaults source] objectForKey: @"SOGoDayEndTime"])
[[defaults source] setObject: [NSString stringWithFormat: @"%02d:00", [defaults dayEndHour]] forKey: @"SOGoDayEndTime"];
if (![[defaults source] objectForKey: @"SOGoFirstWeekOfYear"])
[[defaults source] setObject: [defaults firstWeekOfYear] forKey: @"SOGoFirstWeekOfYear"];
@@ -115,20 +114,20 @@ static SoProduct *preferencesProduct = nil;
if (![[defaults source] objectForKey: @"SOGoCalendarEventsDefaultClassification"])
[[defaults source] setObject: [defaults calendarEventsDefaultClassification] forKey: @"SOGoCalendarEventsDefaultClassification"];
if (![[defaults source] objectForKey: @"SOGoCalendarTasksDefaultClassification"])
[[defaults source] setObject: [defaults calendarTasksDefaultClassification] forKey: @"SOGoCalendarTasksDefaultClassification"];
if (![[defaults source] objectForKey: @"SOGoCalendarDefaultReminder"])
[[defaults source] setObject: [defaults calendarDefaultReminder] forKey: @"SOGoCalendarDefaultReminder"];
// Populate default calendar categories, based on the user's preferred language
if (![defaults calendarCategories])
{
categoryLabels = [[[self labelForKey: @"calendar_category_labels" withResourceManager: [preferencesProduct resourceManager]]
componentsSeparatedByString: @","]
sortedArrayUsingSelector: @selector (localizedCaseInsensitiveCompare:)];
[defaults setCalendarCategories: categoryLabels];
}
if (![defaults calendarCategoriesColors])
@@ -144,7 +143,7 @@ static SoProduct *preferencesProduct = nil;
[defaults setCalendarCategoriesColors: colors];
}
//
// Default Contacts preferences
//
@@ -155,10 +154,10 @@ static SoProduct *preferencesProduct = nil;
categoryLabels = [[[self labelForKey: @"contacts_category_labels" withResourceManager: [preferencesProduct resourceManager]]
componentsSeparatedByString: @","]
sortedArrayUsingSelector: @selector (localizedCaseInsensitiveCompare:)];
if (!categoryLabels)
categoryLabels = [NSArray array];
[defaults setContactsCategories: categoryLabels];
}
@@ -173,27 +172,27 @@ static SoProduct *preferencesProduct = nil;
if (![[defaults source] objectForKey: @"SOGoMailReplyPlacement"])
[[defaults source] setObject: [defaults mailReplyPlacement] forKey: @"SOGoMailReplyPlacement"];
if (![[defaults source] objectForKey: @"SOGoMailSignaturePlacement"])
[[defaults source] setObject: [defaults mailSignaturePlacement] forKey: @"SOGoMailSignaturePlacement"];
if (![[defaults source] objectForKey: @"SOGoMailComposeMessageType"])
[[defaults source] setObject: [defaults mailComposeMessageType] forKey: @"SOGoMailComposeMessageType"];
if (![[defaults source] objectForKey: @"SOGoMailDisplayRemoteInlineImages"])
[[defaults source] setObject: [defaults mailDisplayRemoteInlineImages] forKey: @"SOGoMailDisplayRemoteInlineImages"];
// Populate default mail lablels, based on the user's preferred language
if (![[defaults source] objectForKey: @"SOGoMailLabelsColors"])
{
SOGoMailLabel *label;
NSArray *labels;
id v;
int i;
v = [defaults mailLabelsColors];
labels = [SOGoMailLabel labelsFromDefaults: v component: self];
v = [NSMutableDictionary dictionary];
for (i = 0; i < [labels count]; i++)
@@ -202,7 +201,7 @@ static SoProduct *preferencesProduct = nil;
[v setObject: [NSArray arrayWithObjects: [label label], [label color], nil]
forKey: [label name]];
}
[defaults setMailLabelsColors: v];
}
@@ -215,10 +214,6 @@ static SoProduct *preferencesProduct = nil;
//
values = [[[[defaults source] values] mutableCopy] autorelease];
// Add locale code (used by CK Editor)
locale = [[preferencesProduct resourceManager] localeForLanguageNamed: [defaults language]];
[values setObject: [locale objectForKey: @"NSLocaleCode"] forKey: @"LocaleCode"];
accounts = [NSMutableArray arrayWithArray: [values objectForKey: @"AuxiliaryMailAccounts"]];
account = [[[context activeUser] mailAccounts] objectAtIndex: 0];
if (![account objectForKey: @"receipts"])
@@ -255,16 +250,6 @@ static SoProduct *preferencesProduct = nil;
forKey: @"PreventInvitationsWhitelist"];
}
// Initialize some default values
if (![settings objectForKey: @"Calendar"])
[settings setObject: [NSMutableDictionary dictionary] forKey: @"Calendar"];
if (![settings objectForKey: @"Contact"])
[settings setObject: [NSMutableDictionary dictionary] forKey: @"Contact"];
if (![settings objectForKey: @"Mail"])
[settings setObject: [NSMutableDictionary dictionary] forKey: @"Mail"];
return [self _makeResponse: [[settings source] values]];
}
+1 -1
View File
@@ -1064,7 +1064,7 @@ static NSArray *reminderValues = nil;
if (!capabilities)
{
if ([self isSieveScriptsEnabled] && [self _sieveClient])
if ([self _sieveClient])
capabilities = [[self _sieveClient] capabilities];
else
capabilities = [NSArray array];
+20 -49
View File
@@ -94,7 +94,7 @@ static NSArray *tasksFields = nil;
@"c_classification", @"c_category",
@"c_partmails", @"c_partstates", @"c_owner",
@"c_iscycle", @"c_nextalarm",
@"c_recurrence_id", @"isException", @"viewable", @"editable",
@"c_recurrence_id", @"isException", @"editable",
@"erasable", @"ownerIsOrganizer", @"c_description", nil];
[eventsFields retain];
}
@@ -104,7 +104,7 @@ static NSArray *tasksFields = nil;
@"calendarName",
@"c_status", @"c_title", @"c_enddate",
@"c_classification", @"c_location", @"c_category",
@"viewable", @"editable", @"erasable",
@"editable", @"erasable",
@"c_priority", @"c_owner",
@"c_iscycle", @"c_nextalarm",
@"c_recurrence_id", @"isException", @"c_description", nil];
@@ -258,7 +258,7 @@ static NSArray *tasksFields = nil;
labelKey = [NSString stringWithFormat: @"%@_class%@",
type, [component objectForKey: @"c_classification"]];
[component setObject: [self labelForKey: labelKey inContext: context]
[component setObject: [self labelForKey: labelKey]
forKey: @"c_title"];
}
@@ -441,35 +441,21 @@ static NSArray *tasksFields = nil;
}
else
{
currentInfos = [[currentFolder fetchCoreInfosFrom: startDate
id foo;
foo = [currentFolder fetchCoreInfosFrom: startDate
to: endDate
title: value
component: component]
objectEnumerator];
component: component];
currentInfos = [foo objectEnumerator];
}
owner = [currentFolder ownerInContext: context];
ownerUser = [SOGoUser userWithLogin: owner];
isErasable = ([owner isEqualToString: userLogin] || [[currentFolder aclsForUser: userLogin] containsObject: SOGoRole_ObjectEraser]);
while ((newInfo = [currentInfos nextObject]))
{
if ([fields containsObject: @"viewable"])
{
if ([owner isEqualToString: userLogin])
[newInfo setObject: [NSNumber numberWithInt: 1] forKey: @"viewable"];
else
{
role = [currentFolder roleForComponentsWithAccessClass: [[newInfo objectForKey: @"c_classification"] intValue]
forUser : userLogin];
if ([role isEqualToString: @"ComponentViewer"])
[newInfo setObject: [NSNumber numberWithInt: 1] forKey: @"viewable"];
else
[newInfo setObject: [NSNumber numberWithInt: 0] forKey: @"viewable"];
}
}
if ([fields containsObject: @"editable"])
{
if (folderIsRemote)
@@ -562,19 +548,19 @@ static NSArray *tasksFields = nil;
{
// Same day
if (forAllDay)
return [self labelForKey: @"Today" inContext: context];
return [self labelForKey: @"Today"];
else
return [dateFormatter formattedTime: date];
}
else if ([now dayOfCommonEra] - [date dayOfCommonEra] == 1)
{
// Yesterday
return [self labelForKey: @"Yesterday" inContext: context];
return [self labelForKey: @"Yesterday"];
}
else if ([date dayOfCommonEra] - [now dayOfCommonEra] == 1)
{
// Tomorrow
return [self labelForKey: @"Tomorrow" inContext: context];
return [self labelForKey: @"Tomorrow"];
}
else if (abs(delta = [date dayOfCommonEra] - [now dayOfCommonEra]) < 7)
{
@@ -587,7 +573,7 @@ static NSArray *tasksFields = nil;
return dayOfWeek;
else
// With the past 7 days
return [NSString stringWithFormat: [self labelForKey: @"last %@" inContext: context], dayOfWeek];
return [NSString stringWithFormat: [self labelForKey: @"last %@"], dayOfWeek];
}
else
{
@@ -666,11 +652,10 @@ static NSArray *tasksFields = nil;
return [self _responseWithData: data];
}
- (void) saveFilterValue: (NSString *) submodule
- (void) saveFilterValue
{
NSString *filter;
SOGoUserSettings *us;
NSMutableDictionary *calendarSettings;
filter = [[context request] formValueForKey: @"filterpopup"];
if ([filter length]
@@ -678,20 +663,12 @@ static NSArray *tasksFields = nil;
&& ![filter isEqualToString: @"view_future"])
{
us = [[context activeUser] userSettings];
calendarSettings = [us objectForKey: @"Calendar"];
// Must create if it doesn't exist
if (!calendarSettings)
{
calendarSettings = [NSMutableDictionary dictionary];
[us setObject: calendarSettings forKey: @"Calendar"];
}
//[us setObject: filter forKey: submodule];
[calendarSettings setObject: filter forKey: submodule];
[us setObject: filter forKey: @"CalendarDefaultFilter"];
[us synchronize];
}
}
- (void) saveSortValue: (NSString *) submodule
- (void) saveSortValue
{
NSString *sort, *ascending;
SOGoUserSettings *us;
@@ -709,8 +686,7 @@ static NSArray *tasksFields = nil;
calendarSettings = [NSMutableDictionary dictionary];
[us setObject: calendarSettings forKey: @"Calendar"];
}
[calendarSettings setObject: [NSArray arrayWithObjects: [sort lowercaseString], [NSString stringWithFormat: @"%d", [ascending intValue]], nil]
forKey: submodule];
[calendarSettings setObject: [NSArray arrayWithObjects: [sort lowercaseString], [NSString stringWithFormat: @"%d", (ascending?1:0)], nil] forKey: @"EventsSortingState"];
[us synchronize];
}
}
@@ -746,11 +722,10 @@ static NSArray *tasksFields = nil;
* @apiSuccess (Success 200) {String[]} events.c_partmails Participants email addresses
* @apiSuccess (Success 200) {String[]} events.c_partstates Participants states
* @apiSuccess (Success 200) {String} events.c_owner Event's owner
* @apiSuccess (Success 200) {Number} events.c_iscycle 1 if the event is cyclic/recurring
* @apiSuccess (Success 200) {Number} events.c_iscycle 1 if the event is cyclic
* @apiSuccess (Success 200) {Number} events.c_nextalarm Epoch time of next alarm
* @apiSuccess (Success 200) {String} [events.c_recurrence_id] Recurrence ID if event is cyclic
* @apiSuccess (Success 200) {Number} events.isException 1 if recurrence is an exception
* @apiSuccess (Success 200) {Number} events.viewable 1 if active user can view the event
* @apiSuccess (Success 200) {Number} events.editable 1 if active user can edit the event
* @apiSuccess (Success 200) {Number} events.erasable 1 if active user can erase the event
* @apiSuccess (Success 200) {Number} events.ownerIsOrganizer 1 if owner is also the organizer
@@ -768,8 +743,8 @@ static NSArray *tasksFields = nil;
NSString *sort, *ascending;
[self _setupContext];
[self saveFilterValue: @"EventsFilterState"];
[self saveSortValue: @"EventsSortingState"];
[self saveFilterValue];
[self saveSortValue];
newEvents = [NSMutableArray array];
events = [[self _fetchFields: eventsFields
@@ -1269,7 +1244,6 @@ _computeBlocksPosition (NSArray *blocks)
* @apiSuccess (Success 200) {Number} events.c_nextalarm Epoch time of next alarm
* @apiSuccess (Success 200) {String} [events.c_recurrence_id] Recurrence ID if event is cyclic
* @apiSuccess (Success 200) {Number} events.isException 1 if recurrence is an exception
* @apiSuccess (Success 200) {Number} events.viewable 1 if active user can view the event
* @apiSuccess (Success 200) {Number} events.editable 1 if active user can edit the event
* @apiSuccess (Success 200) {Number} events.erasable 1 if active user can erase the event
* @apiSuccess (Success 200) {Number} events.ownerIsOrganizer 1 if owner is also the organizer
@@ -1434,7 +1408,6 @@ _computeBlocksPosition (NSArray *blocks)
* @apiSuccess (Success 200) {Number} tasks.c_classification 0: Public, 1: Private, 2: Confidential
* @apiSuccess (Success 200) {String} tasks.c_location Location
* @apiSuccess (Success 200) {String} tasks.c_category Category
* @apiSuccess (Success 200) {Number} tasks.viewable 1 if task is viewable by the active user
* @apiSuccess (Success 200) {Number} tasks.editable 1 if task is editable by the active user
* @apiSuccess (Success 200) {Number} tasks.erasable 1 if task is erasable by the active user
* @apiSuccess (Success 200) {String} tasks.c_priority Priority (0-9)
@@ -1463,8 +1436,6 @@ _computeBlocksPosition (NSArray *blocks)
filteredTasks = [NSMutableArray array];
[self _setupContext];
[self saveFilterValue: @"TasksFilterState"];
[self saveSortValue: @"TasksSortingState"];
startSecs = (unsigned int) [startDate timeIntervalSince1970];
endsSecs = (unsigned int) [endDate timeIntervalSince1970];
+1 -4
View File
@@ -33,7 +33,6 @@
#import <NGCards/iCalPerson.h>
#import <SOGo/NSArray+Utilities.h>
#import <SOGo/NSString+Utilities.h>
#import <SOGo/SOGoPermissions.h>
#import <SOGo/SOGoUser.h>
#import <SOGo/SOGoUserDefaults.h>
@@ -262,14 +261,12 @@
- (WOResponse *) saveSelectedListAction
{
WORequest *request;
NSDictionary *params;
NSString *selectedList;
[self _setupContext];
request = [context request];
params = [[request contentAsString] objectFromJSONString];
selectedList = [params objectForKey: @"list"];
selectedList = [request formValueForKey: @"list"];
[moduleSettings setObject: selectedList
forKey: @"SelectedList"];
[us synchronize];
@@ -20,6 +20,14 @@
#import <SOGoUI/UIxComponent.h>
@class NSString;
@class SOGoAppointmentFolder;
@interface UIxCalendarFolderLinksTemplate : UIxComponent
{
SOGoAppointmentFolder *calendar;
NSString *baseCalDAVURL, *basePublicCalDAVURL;
}
@end
@@ -28,6 +28,89 @@
@implementation UIxCalendarFolderLinksTemplate
- (id) init
{
if ((self = [super init]))
{
calendar = [self clientObject];
baseCalDAVURL = nil;
basePublicCalDAVURL = nil;
}
return self;
}
- (void) dealloc
{
[baseCalDAVURL release];
[basePublicCalDAVURL release];
[super dealloc];
}
- (NSString *) _baseCalDAVURL
{
NSString *davURL;
if (!baseCalDAVURL)
{
davURL = [[calendar realDavURL] absoluteString];
if ([davURL hasSuffix: @"/"])
baseCalDAVURL = [davURL substringToIndex: [davURL length] - 1];
else
baseCalDAVURL = davURL;
[baseCalDAVURL retain];
}
return baseCalDAVURL;
}
- (NSString *) calDavURL
{
return [NSString stringWithFormat: @"%@/", [self _baseCalDAVURL]];
}
- (NSString *) webDavICSURL
{
return [calendar webDavICSURL];
}
- (NSString *) webDavXMLURL
{
return [calendar webDavXMLURL];
}
- (NSString *) _basePublicCalDAVURL
{
NSString *davURL;
if (!basePublicCalDAVURL)
{
davURL = [[calendar publicDavURL] absoluteString];
if ([davURL hasSuffix: @"/"])
basePublicCalDAVURL = [davURL substringToIndex: [davURL length] - 1];
else
basePublicCalDAVURL = davURL;
[basePublicCalDAVURL retain];
}
return basePublicCalDAVURL;
}
- (NSString *) publicCalDavURL
{
return [NSString stringWithFormat: @"%@/", [self _basePublicCalDAVURL]];
}
- (NSString *) publicWebDavICSURL
{
return [calendar publicWebDavICSURL];
}
- (NSString *) publicWebDavXMLURL
{
return [calendar publicWebDavXMLURL];
}
- (BOOL) isPublicAccessEnabled
{
// NOTE: This method is the same found in Common/UIxAclEditor.m
@@ -35,4 +118,14 @@
enablePublicAccess];
}
- (BOOL) isWebCalendar
{
return ([calendar isKindOfClass: [SOGoWebAppointmentFolder class]]);
}
- (NSString *) webCalendarURL
{
return [calendar folderPropertyValueInCategory: @"WebCalendars"];
}
@end
+1 -1
View File
@@ -842,7 +842,7 @@ static NSArray *reminderValues = nil;
clientObject = [self clientObject];
ownerUser = [SOGoUser userWithLogin: [clientObject ownerInContext: context]];
if ([[clientObject container] isKindOfClass: [SOGoWebAppointmentFolder class]])
if ([clientObject isKindOfClass: [SOGoWebAppointmentFolder class]])
rc = componentReadableOnly;
else
{
+1 -1
View File
@@ -193,7 +193,7 @@
actionName = "saveUserRights";
};
links = {
protectedBy = "Access Contents Information";
protectedBy = "View";
pageName = "UIxCalendarFolderLinksTemplate";
};
};
@@ -5,8 +5,8 @@
xmlns:const="http://www.skyrix.com/od/constant"
xmlns:label="OGo:label">
<md-content md-scroll-y="md-scroll-y" class="viewer md-padding md-whiteframe-z1 bg-sogoPaper-50">
<!-- <div class="editor md-padding">-->
<md-content md-scroll-y="true" class="md-padding md-whiteframe-z1 bg-sogoPaper-50">
<div class="editor md-padding">
<hgroup class="header">
<h1 class="sg-md-display-2--light" ng-bind-html="editor.card.$fullname()"><!-- fullname --></h1>
<h6 class="sg-md-display-2-subheader">{{editor.card.$description()}}</h6>
@@ -115,6 +115,7 @@
<md-icon>remove_circle</md-icon>
</md-button>
</div>
</div>
<div class="md-layout-margin" layout="row" layout-align="start center">
<md-button class="sg-icon-button" type="button" ng-click="editor.addEmail()">
@@ -127,25 +128,12 @@
</div>
<!-- birthday -->
<div class="section">
<div layout="row" layout-align="space-between end" ng-show="editor.card.birthday">
<label>
<var:string label:value="Birthday"/>
</label>
<md-datepicker ng-model="editor.card.birthday"><!-- birthday --></md-datepicker>
<md-button class="sg-icon-button" type="button" ng-click="editor.card.$delete('birthday', -1)">
<md-icon>remove_circle</md-icon>
</md-button>
</div>
<div class="md-layout-margin" layout="row" layout-align="start center" ng-hide="editor.card.birthday">
<md-button class="sg-icon-button" type="button" ng-click="editor.addBirthday()">
<md-icon>add_circle</md-icon>
</md-button>
<label class="button-label">
<var:string label:value="Add Birthday"/>
</label>
</div>
</div>
<md-input-container>
<label>
<var:string label:value="Birthday"/>
</label>
<input type="date" ng-model="editor.card.birthday"/>
</md-input-container>
<!-- phones -->
<div class="section">
@@ -354,7 +342,7 @@
</var:if>
</div>
</form>
<!-- </div> -->
</div>
</md-content>
</container>
@@ -6,15 +6,14 @@
xmlns:const="http://www.skyrix.com/od/constant"
xmlns:label="OGo:label"
>
<md-dialog flex="60" flex-sm="100">
<md-dialog flex="40">
<md-toolbar class="sg-padded">
<md-icon class="material-icons sg-icon-toolbar-bg">link</md-icon>
<div class="md-toolbar-tools">
<div class="pseudo-input-container md-flex">
<label class="pseudo-input-label"><var:string label:value="Links to this Address Book"/></label>
<div class="pseudo-input-field sg-md-title">{{links.addressbook.name}}</div>
<div class="pseudo-input-field sg-md-title"><var:string value="addressBook.displayName"/></div>
</div>
<md-button class="md-icon-button" ng-click="links.close()">
<md-button class="md-icon-button" ng-click="close()">
<md-icon aria-label="Close dialog">close</md-icon>
</md-button>
</div>
@@ -25,7 +24,7 @@
<div class="sg-md-title"><var:string label:value="Authenticated User Access"/></div>
<md-input-container>
<label><var:string label:value="CardDAV URL"/></label>
<input type="text" ng-model="links.addressbook.urls.cardDavURL" ng-readonly="true"/>
<input var:value="cardDavURL" ng-readonly="true"/>
</md-input-container>
</div>
<var:if condition="isPublicAccessEnabled">
@@ -33,7 +32,7 @@
<div class="sg-md-title"><var:string label:value="Public Access"/></div>
<md-input-container>
<label><var:string label:value="CardDAV URL"/></label>
<input type="text" ng-model="links.addressbook.urls.publicCardDavURL" ng-readonly="true"/>
<input var:value="publicCardDavURL" ng-readonly="true"/>
</md-input-container>
</div>
</var:if>
+131 -93
View File
@@ -9,16 +9,94 @@
className="UIxPageFrame"
title="title"
const:userDefaultsKeys="SOGoContactsCategories"
const:jsFiles="vendor/ckeditor/ckeditor.js, vendor/ckeditor/ck.js, Common.js, Preferences.services.js, Mailer.services.js, Contacts.js, Contacts.services.js, vendor/angular-file-upload.min.js">
const:jsFiles="Common.js, Preferences.services.js, Contacts.js, Contacts.services.js">
<script type="text/javascript">
var contactFolders = <var:string value="contactFolders" const:escapeHTML="NO" />;
</script>
<main class="view layout-fill" ui-view="addressbooks" layout="row" ng-controller="navController"><!-- addressbooks list --></main>
<!--
<div id="uploadDialog" style="display: none" class="dialog left">
<div>
<h3><var:string label:value="Import Cards"/></h3>
<p class="prompt"><var:string label:value="Select a vCard or LDIF file."/></p>
<form const:href="" name="uploadForm" id="uploadForm" method="post"
enctype="multipart/form-data"
onsubmit="return AIM.submit(this, {'onStart' : validateUploadForm,
'onComplete' : uploadCompleted})">
<p class="prompt"><input type="file" name="contactsFile" id="contactsFile" class="textField" required="required" />
<a href="#" class="button actionButton" id="uploadSubmit"
onclick="if($('uploadForm').onsubmit()) $('uploadForm').submit()">
<span><var:string label:value="Upload" /></span></a>
<a href="#" class="button" const:id="uploadCancel">
<span><var:string label:value="Cancel" /></span></a></p>
</form>
<hr/>
</div>
</div>
<div id="uploadResults" dropdown-content="dropdown-content" class="f-dropdown">
<div>
<h3><var:string label:value="Import Cards"/></h3>
<p id="uploadResultsContent">!- empty -</p>
<p><a href="#" class="button" const:id="uploadOK">
<span><var:string label:value="Done" /></span></a></p>
<hr/>
</div>
</div>
<ul class="f-dropdown" dropdown-content="dropdown-content" id="contactMenu">
<li><var:string label:value="Properties" /></li>
<li><var:string label:value="Categories" /></li>
<li>!- separator -</li>
<li><var:string label:value="Write" /></li>
<li><var:string label:value="Instant Message" /></li>
<li>!- separator -</li>
<li><var:string label:value="Delete" /></li>
<li>!- separator -</li>
<li><var:string label:value="Move To" /></li>
<li><var:string label:value="Copy To" /></li>
<li><var:string label:value="Export" /></li>
<li><var:string label:value="View Raw Source" /></li>
</ul>
-->
<!--
MAIN CONTENT ROW
Content of the application view injected injected in the element bellow
MUST be the first html element after body
SHOULD be a main tag (with role="main")
Templates script tag wrappers goes next
-->
<main class="view md-layout-fill" ui-view="addressbooks" layout="row" ng-controller="navController"><!-- addressbooks list --></main>
<!-- TEMPLATE SCRIPT WRAPPER -->
<script type="text/ng-template" id="UIxContactFoldersView">
<!-- dropdown menu for addressbook options button -->
<div id="addressbookProperties" class="f-dropdown icons-dropdown" ng-hide="true">
<ul class="button-group">
<li label:tooltip="Links to this Address Book"
tooltip-popup-delay="500">
<span class="button"
sg-dropdown-content-toggle="#addressbookLinks">
<i class="icon-hyperlink"><!-- links --></i>
</span>
</li>
<li label:tooltip="Rename"
tooltip-popup-delay="500">
<span class="button" ng-click="edit()">
<i class="icon-pencil"><!-- rename --></i>
</span>
</li>
<li label:tooltip="Import Cards"
tooltip-popup-delay="500">
<span class="button" ng-click="importCards()">
<i class="icon-file"><!-- import --></i>
</span>
</li>
</ul>
</div>
<!-- Sidenav -->
<md-sidenav id="left-sidenav" class="md-sidenav-left md-whiteframe-z1" md-component-id="left" md-is-locked-open="isGtMedium" layout="column">
<var:component className="UIxSidenavToolbarTemplate" />
@@ -28,7 +106,7 @@
<section>
<md-subheader class="sg-md-subheader">
<div layout="row" layout-align="space-between center">
<span><var:string label:value="Address Books"/></span>
<span><var:string label:value="AddressBooks"/></span>
<md-button class="sg-icon-button"
label:aria-label="New Addressbook..."
ng-click="app.newAddressbook()">
@@ -62,22 +140,11 @@
ng-click="$mdOpenMenu()"
md-menu-origin="md-menu-origin">more_vert</md-icon>
<md-menu-content width="2">
<md-menu-item>
<md-button type="button" ng-click="app.edit(folder)">
<var:string label:value="Rename"/>
</md-button>
</md-menu-item>
<md-menu-item>
<md-button type="button" ng-click="app.confirmDelete()">
<var:string label:value="Delete"/>
</md-button>
</md-menu-item>
<md-menu-divider><!-- divider --></md-menu-divider>
<md-menu-item>
<md-button type="button" ng-click="app.importCards($event, folder)">
<var:string label:value="Import"/>
</md-button>
</md-menu-item>
<md-menu-item>
<md-button type="button" ng-click="app.exportCards()">
<var:string label:value="Export"/>
@@ -138,11 +205,6 @@
ng-click="$mdOpenMenu()"
md-menu-origin="md-menu-origin">more_vert</md-icon>
<md-menu-content width="2">
<md-menu-item>
<md-button type="button" ng-click="app.edit(folder)">
<var:string label:value="Rename"/>
</md-button>
</md-menu-item>
<md-menu-item>
<md-button type="button" ng-click="app.confirmDelete(folder)">
<var:string label:value="Delete"/>
@@ -172,16 +234,17 @@
<!-- </div> -->
</md-sidenav>
<section layout="column" class="sg-app-content layout-fill" ui-view="addressbook"><!-- contacts list --></section>
<section layout="column" class="sg-app-content md-layout-fill" ui-view="addressbook"><!-- contacts list --></section>
</script>
<script type="text/ng-template" id="addressbook">
<md-toolbar layout="column" layout-align="space-between start" class="md-tall toolbar-main">
<div class="md-toolbar-tools md-toolbar-tools-top" layout="row" layout-align="space-between start">
<div class="md-toolbar-tools md-toolbar-tools-top sg-padded" layout="row" layout-align="space-between start">
<var:component className="UIxTopnavToolbarTemplate" />
</div>
<div class="md-toolbar-tools" layout="row" layout-align="space-between center"
ng-show="addressbook.selectedFolder.$selectedCount() == 0">
<div class="view-list" layout="row" layout-align="space-between center"
ng-hide="addressbook.mode.search">
<div class="sg-toolbar-group">
@@ -232,10 +295,9 @@
</md-menu-item>
<md-menu-divider> <!-- divider --></md-menu-divider>
<md-menu-item >
<md-button ng-href="#">
<md-button ng-click="addressbook.sort()">
<md-checkbox
ng-change="addressbook.sort(addressbook.selectedFolder.constructor.$query.sort)"
ng-model="addressbook.selectedFolder.constructor.$query.asc"
ng-model="addressbook.selectedFolder.$query.asc"
ng-true-value="0"
ng-false-value="1"><var:string label:value="Descending Order"/></md-checkbox>
</md-button>
@@ -268,51 +330,26 @@
</md-input-container>
</div>
</div>
<!-- multiple selection mode -->
<div class="md-toolbar-tools" layout="row" layout-align="space-between center"
ng-show="addressbook.selectedFolder.$selectedCount() > 0">
<div class="view-list" layout="row" layout-align="space-between center">
<div class="sg-toolbar-group">
<md-button class="sg-icon-button" ng-click="addressbook.unselectCards()">
<md-icon>arrow_back</md-icon>
</md-button>
<label>{{addressbook.selectedFolder.$selectedCount()}} <var:string label:value="selected"/></label>
</div>
<div class="sg-toolbar-group-last">
<div layout="row" layout-align="start center" ng-show="addressbook.selectedFolder.$selectedCount() > 0">
<md-button class="sg-icon-button" ng-click="addressbook.unselectCards()">
<md-icon>arrow_back</md-icon>
</md-button>
<label>{{addressbook.selectedFolder.$selectedCount()}} selected</label>
<md-button class="sg-icon-button" ng-click="addressbook.selectAll()">
<md-tooltip md-direction="left"><var:string label:value="Select All"/></md-tooltip>
<md-icon>select_all</md-icon>
</md-button>
<md-button class="sg-icon-button"
ng-show="addressbook.selectedFolder.acls.objectEraser"
ng-click="addressbook.confirmDeleteSelectedCards()">
<md-button class="sg-icon-button" ng-click="addressbook.confirmDeleteSelectedCards()">
<md-icon>delete</md-icon>
</md-button>
<md-menu>
<md-button class="sg-icon-button" label:aria-label="Copy contacts" ng-click="$mdOpenMenu()">
<md-tooltip md-direction="left"><var:string label:value="Copy To"/></md-tooltip>
<md-icon>content_copy</md-icon>
</md-button>
<md-menu-content width="4">
<md-menu-item>
<md-button class="md-primary" ng-disabled="true"><var:string label:value="Address Books"/></md-button>
</md-menu-item>
<md-menu-divider><!-- divider --></md-menu-divider>
<md-menu-item ng-repeat="folder in app.service.$addressbooks track by folder.id"
ng-hide="addressbook.selectedFolder.id == folder.id">
<md-button ng-click="addressbook.copySelectedCards(folder.id)">
<span ng-class="'sg-child-level-' + folder.level">{{folder.name}}</span>
</md-button>
</md-menu-item>
</md-menu-content>
</md-menu>
<md-menu>
<md-button class="sg-icon-button" label:aria-label="More messages options" ng-click="$mdOpenMenu()">
<md-icon>more_vert</md-icon>
</md-button>
<md-menu-content width="2">
<md-menu-item>
<md-button ng-click="addressbook.newMessageWithSelectedCards($event)">
<md-button>
<var:string label:value="Write"/>
</md-button>
</md-menu-item>
@@ -323,11 +360,9 @@
</md-menu-item>
</md-menu-content>
</md-menu>
</div>
</div>
</div>
</md-toolbar>
<div layout="row" class="md-flex">
<div layout="row" class="md-flex" layout-align="space-between">
<div class="view-list" layout="column">
<md-content id="contactsList" layout="column" class="md-flex">
<header class="sg-md-subheader sg-md-subheader--fixed">
@@ -336,59 +371,62 @@
<span ng-show="addressbook.selectedFolder.cards.length == 0"><var:string label:value="No contact"/></span>
</h2>
</header>
<!-- Search field & special results
<input type="text" placeholder="Search" ng-model="search.filter" ng-keyup="doSearch($event)" />
<div ng-switch="search.status">
<div ng-switch-when="min-char" class="alert-bg">
<i class="icon-warning"></i><var:string label:value="Please enter at least three characters"/>
</div>
<div ng-switch-when="no-result" class="alert-bg">
<i class="icon-ion-search"></i><var:string label:value="No matching card"/>
</div>
<div ng-switch-when="remote-addressbook" ng-show="addressbook.cards.length == 0" class="alert-bg">
<i class="icon-ion-search"></i><var:string label:value="Initiate a search"/>
</div>
</div>
-->
<md-virtual-repeat-container class="md-flex">
<md-list class="sg-section-list">
<div md-virtual-repeat="currentCard in addressbook.selectedFolder.cards" md-item-size="72">
<md-list>
<div md-virtual-repeat="currentCard in addressbook.selectedFolder.cards">
<md-list-item
ng-class="{'sg-active': currentCard.id == addressbook.selectedFolder.selectedCard}"
ng-click="addressbook.selectCard(currentCard)"
ui-sref="app.addressbook.card.view({addressbookId: addressbook.selectedFolder.id, cardId: currentCard.id})">
<div class="sg-selected-avatar" ng-show="currentCard.selected"
ng-click="currentCard.selected = !currentCard.selected">
<!-- selected avatar -->
</div>
<sg-avatar-image class="md-tile-left"
ng-show="addressbook.notSelectedComponent(currentCard, 'vcard')"
ng-click="currentCard.selected = !currentCard.selected"
sg-email="currentCard.$preferredEmail(addressbook.selectedFolder.constructor.$query)"
size="40">
<!-- contact avatar -->
</sg-avatar-image>
<div class="sg-list-avatar"
ng-show="addressbook.notSelectedComponent(currentCard, 'vlist')"
ng-click="currentCard.selected = !currentCard.selected">
<!-- list avatar -->
</div>
<!-- ui-sref-active="sg-active" -->
<div class="sg-selected-avatar" ng-show="currentCard.selected"
ng-click="currentCard.selected = !currentCard.selected">
<!-- selected avatar -->
</div>
<sg-avatar-image class="md-tile-left"
ng-show="addressbook.notSelectedComponent(currentCard, 'vcard')"
ng-click="currentCard.selected = !currentCard.selected"
sg-email="currentCard.$preferredEmail(addressbook.selectedFolder.$query)"
size="48">
<!-- contact avatar -->
</sg-avatar-image>
<div class="sg-list-avatar"
ng-show="addressbook.notSelectedComponent(currentCard, 'vlist')"
ng-click="currentCard.selected = !currentCard.selected">
<!-- list avatar -->
</div>
<div class="sg-tile-content">
<div class="sg-md-subhead-multi" ng-bind-html="currentCard.$fullname()"><!-- cn --></div>
<div class="sg-md-body-multi">{{currentCard.$preferredEmail(addressbook.selectedFolder.constructor.$query)}}</div>
<div class="sg-md-body-multi">{{currentCard.$preferredEmail(addressbook.selectedFolder.$query)}}</div>
</div>
</md-list-item>
</div>
</md-list>
</md-virtual-repeat-container>
<div class="sg-progress-circular-floating"
ng-show="addressbook.selectedFolder.$isLoading">
<md-progress-circular class="md-accent"
md-mode="indeterminate"
md-diameter="32"><!-- progress --></md-progress-circular>
</div>
<md-button class="md-fab md-fab-bottom-right md-accent"
label:aria-label="New Contact"
ng-show="addressbook.selectedFolder.acls.objectCreator"
ng-click="addressbook.newComponent($event)">
<md-icon>add</md-icon>
</md-button>
</md-content>
</div>
<md-content id="detailView" class="view-detail md-hue-1" layout="column" layout-align="center center"
ng-class="{ 'sg-close': !addressbook.selectedFolder.selectedCard }"
ui-view="card">
<md-input-container class="hide-sm md-hue-1" style="flex-grow: 0">
<label class="sg-md-title"><var:string label:value="No contact selected"/></label>
</md-input-container>
</md-content>
<div id="detailView" class="view-detail ng-cloak" layout="column" ui-view="card"
ng-show="addressbook.selectedFolder.selectedCard"><!-- card view --></div>
</div>
</script>
@@ -5,7 +5,7 @@
xmlns:const="http://www.skyrix.com/od/constant"
xmlns:label="OGo:label"
>
<md-card class="viewer flex-sm">
<md-card class="viewer md-flex">
<md-card-content>
<header class="msg-header">
<div ng-show="editor.card.tag == 'vcard'">
@@ -30,19 +30,18 @@
<div class="sg-icon-bar--vertical">
<md-button class="sg-icon-button show-sm"
label:aria-label="Close"
ng-click="editor.close()">
ng-click="toggleDetailView()">
<md-icon>close</md-icon>
</md-button>
<md-button class="sg-icon-button"
label:aria-label="Edit"
ng-show="editor.currentFolder.acls.objectEditor"
ng-show="editor.currentFolder.isEditable"
ui-sref="app.addressbook.card.editor({addressbookId: editor.currentFolder.id, cardId: editor.card.id})">
<md-tooltip md-direction="left"><var:string label:value="Edit"/></md-tooltip>
<md-icon>mode_edit</md-icon>
</md-button>
<md-button class="sg-icon-button"
label:aria-label="Delete"
ng-show="editor.currentFolder.acls.objectEraser"
ng-click="editor.confirmDelete(editor.card)">
<md-tooltip md-direction="left"><var:string label:value="Delete"/></md-tooltip>
<md-icon>delete</md-icon>
@@ -54,13 +53,7 @@
</md-button>
<md-menu-content>
<md-menu-item>
<md-button label:aria-label="Export"
ng-click="editor.exportCard()">
<var:string label:value="Export"/>
</md-button>
</md-menu-item>
<md-menu-item>
<md-button label:aria-label="View Raw Source"
<md-button aria-label="View Raw Source"
ng-click="editor.viewRawSource($event)">
<var:string label:value="View Raw Source"/>
</md-button>
@@ -72,14 +65,14 @@
</header>
<section class="msg-body">
<div class="pseudo-input-container" ng-show="editor.card.$birthday().length">
<div class="pseudo-input-container" ng-show="editor.card.birthday">
<div class="key">
<label class="pseudo-input-label">
<var:string label:value="Birthday"/>
</label>
</div>
<div class="pseudo-input-field">
<span>{{editor.card.$birthday()}}</span>
<span>{{editor.card.$birthday() | date}}</span>
</div>
</div>
@@ -118,8 +111,7 @@
</div>
<div class="pseudo-input-field">
<a href="#" ng-bind="email.value"
ng-click="addressbook.newMessageWithRecipient($event, email.value, editor.card.$fullname())"><!-- recipient --></a>
<a href="mailto:{{email.value}}">{{email.value}}</a>
</div>
</div>
@@ -173,4 +165,5 @@
</section>
</md-card-content>
</md-card>
</container>
@@ -7,7 +7,6 @@
xmlns:rsrc="OGo:url"
xmlns:label="OGo:label">
<var:string value="cssContent" const:escapeHTML="NO" />
<div class="SOGoHTMLMail-CSS-Delimiter mailer_htmlcontent">
<var:string value="flatContentAsString" const:escapeHTML="NO" />
</div>
<div class="SOGoHTMLMail-CSS-Delimiter mailer_htmlcontent"
><var:string value="flatContentAsString" const:escapeHTML="NO" /></div>
</container>
@@ -250,7 +250,7 @@
<label class="pseudo-input-label"><var:string label:value="Attendees"/></label>
<!-- md-contact-chips don't support "readonly", so we build them using md-chips
in readonly mode and a template similar to the one of md-contact-chips -->
<md-chips class="md-contact-chips sg-readonly"
<md-chips class="md-contact-chips"
ng-model="part.participants"
readonly="true">
<md-chip-template>
@@ -11,14 +11,13 @@
var:title="filenameForDisplay"
class="md-card-image"></img>
<md-card-content>
<p class="md-caption">
<p>
<var:string value="filenameForDisplay" /><br/>
<var:string value="bodyInfo.size" formatter="sizeFormatter"/>
</p>
</md-card-content>
<div class="md-actions" layout="row" layout-align="end center">
<md-button class="sg-icon-button" var:href="pathForDownload">
<md-tooltip md-direction="left"><var:string label:value="Save Attachment"/></md-tooltip>
<md-icon>save</md-icon>
</md-button>
</div>
@@ -4,16 +4,24 @@
xmlns:var="http://www.skyrix.com/od/binding"
xmlns:const="http://www.skyrix.com/od/constant"
xmlns:label="OGo:label">
<md-card>
<md-card-content>
<md-whiteframe class="md-whiteframe-z1" layout="row" layout-align="space-between center">
<div layout="row">
<div>
<img var:src="mimeImageURL"/>
<p class="md-caption">
<var:string value="filenameForDisplay"/><br/>
</div>
<div layout="column" layout-align="start start" layout-padding="layout-padding">
<div>
<var:string value="filenameForDisplay"/>
</div>
<div class="md-caption">
<var:string value="bodyInfo.size" formatter="sizeFormatter"/>
</p>
</md-card-content>
<div class="md-actions" layout="row" layout-align="end center">
<md-button class="sg-icon-button" var:href="pathToAttachment" target="_blank">
</div>
</div>
</div>
<div layout="row" layout-align="end end">
<md-button class="sg-icon-button" var:href="pathToAttachment">
<md-tooltip md-direction="left"><var:string label:value="View Attachment"/></md-tooltip>
<md-icon>open_in_browser</md-icon>
</md-button>
@@ -42,5 +50,5 @@
PartPath: <var:string value="partPath" /><br />
-->
</md-card>
</md-whiteframe>
</div>
+112 -170
View File
@@ -6,238 +6,180 @@
xmlns:label="OGo:label">
<md-dialog flex="80" flex-sm="100">
<md-toolbar class="sg-padded--right">
<md-toolbar class="md-padding">
<!-- TOOLBAR TO SHOW CC/BCC/ATTACHMENT FIELDS -->
<div class="md-toolbar-tools">
<md-icon class="material-icons sg-icon-toolbar-bg">edit</md-icon>
<!-- from -->
<sg-avatar-image class="md-tile-left" hide-sm="hide-sm"
sg-email="editor.message.editable.from"
size="32"><!-- avatar --></sg-avatar-image>
<md-input-container flex="flex">
<label><var:string label:value="From"/></label>
<md-select name="from"
ng-model="editor.message.editable.from">
<md-option ng-value="identity" ng-repeat="identity in editor.identities">{{identity}}</md-option>
</md-select>
</md-input-container>
<div flex-gt-sm="flex-gt-sm"><!-- spacer --></div>
<md-button class="sg-icon-button" ng-click="editor.send()">
<md-icon>send</md-icon>
</md-button>
<md-button class="sg-icon-button" ng-click="editor.message.$save()">
<md-icon>save</md-icon>
</md-button>
<md-button class="sg-icon-button" ng-click="editor.cancel()">
<md-icon>close</md-icon>
<md-button ng-show="editor.hideCc" ng-click="editor.hideCc = false">Cc</md-button>
<md-button ng-show="editor.hideBcc" ng-click="editor.hideBcc = false">Bcc</md-button>
<md-button>
<label for="file-input">
Add files
</label>
</md-button>
<input id="file-input" type="file"
nv-file-select="nv-file-select"
multiple="multiple"
uploader="editor.uploader"
ng-show="false"/>
<md-menu>
<md-button label:aria-label="More mail options" class="iconBtton" ng-click="$mdOpenMenu($event)">
<md-icon>more_vert</md-icon>
</md-button>
<md-menu-content width="4">
<md-menu-item>
<md-button>
<md-checkbox ng-model="editor.message.editable.receipt">
<var:string label:value="Receipt"/>
</md-checkbox>
</md-button>
</md-menu-item>
<md-menu-item>
<div layout="row" layout-align="center center">
<span>
<var:string label:value="Priority"/>
</span>
<md-slider flex="flex"
md-discrete="md-discrete"
ng-model="editor.message.editable.priority"
step="1"
min="1"
max="5"
label:aria-label="Priority">
</md-slider>
</div>
</md-menu-item>
</md-menu-content>
</md-menu>
</div>
</md-toolbar>
<md-dialog-content>
<form>
<header>
<div class="msg-header-content">
<!-- to -->
<!-- FROM / TO / CC/ BCC / SUBJECT / ATTACHMENTS -->
<div class="msg-header-content">
<md-input-container>
<label> <var:string label:value="From"/></label>
<md-select name="from"
ng-model="editor.message.editable.from">
<md-option ng-value="identity" ng-repeat="identity in editor.identities">{{identity}}</md-option>
</md-select>
</md-input-container>
<div class="pseudo-input-container">
<label class="pseudo-input-label">
<var:string label:value="To"/>
</label>
<md-chips ng-model="editor.message.editable.to"
md-on-append="editor.addRecipient($chip)">
<md-chips ng-model="editor.message.editable.to">
<md-autocomplete
class="sg-chips-autocomplete"
md-search-text="editor.autocomplete.to.searchText"
md-selected-item="editor.autocomplete.to.selected"
md-search-text="editor.autocomplete.to.searchText"
md-items="user in editor.contactFilter(editor.autocomplete.to.searchText)"
md-min-length="3"
md-delay="300"
md-no-cache="true"
label:placeholder="Add a recipient">
<md-item-template>
<span class="md-contact-suggestion">
<span class="md-contact-name"
md-highlight-text="editor.autocomplete.to.searchText"
md-highlight-flags="^i">{{user.$$fullname}}</span>
<span class="md-contact-email"
md-highlight-text="editor.autocomplete.to.searchText"
md-highlight-flags="^i">{{user.$$email}}</span>
</span>
</md-item-template>
<span md-highlight-text="editor.autocomplete.to.searchText"
md-highlight-flags="^i">{{user}}</span>
</md-autocomplete>
<md-chip-template>{{$chip}}</md-chip-template>
</md-chips>
</div>
<!-- cc -->
<div class="pseudo-input-container" ng-hide="editor.hideCc">
<label class="pseudo-input-label">
<var:string label:value="Cc"/>
</label>
<md-chips ng-model="editor.message.editable.cc"
md-on-append="editor.addRecipient($chip)">
<md-chips ng-model="editor.message.editable.cc">
<md-autocomplete
class="sg-chips-autocomplete"
md-search-text="editor.autocomplete.cc.searchText"
md-selected-item="editor.autocomplete.cc.selected"
md-search-text="editor.autocomplete.cc.searchText"
md-items="user in editor.contactFilter(editor.autocomplete.cc.searchText)"
label:placeholder="Add a recipient">
<md-item-template>
<span class="md-contact-suggestion">
<span class="md-contact-name"
md-highlight-text="editor.autocomplete.to.searchText"
md-highlight-flags="^i">{{user.$$fullname}}</span>
<span class="md-contact-email"
md-highlight-text="editor.autocomplete.to.searchText"
md-highlight-flags="^i">{{user.$$email}}</span>
</span>
</md-item-template>
<span md-highlight-text="editor.autocomplete.cc.searchText"
md-highlight-flags="^i">{{user}}</span>
</md-autocomplete>
<md-chip-template>{{$chip}}</md-chip-template>
</md-chips>
</div>
<!-- bcc -->
<div class="pseudo-input-container" ng-hide="editor.hideBcc">
<label class="pseudo-input-label">
<var:string label:value="Bcc"/>
</label>
<md-chips ng-model="editor.message.editable.bcc"
md-on-append="editor.addRecipient($chip)">
<md-chips ng-model="editor.message.editable.bcc">
<md-autocomplete
class="sg-chips-autocomplete"
md-selected-item="editor.autocomplete.bcc.selected"
md-search-text="editor.autocomplete.bcc.searchText"
md-items="user in editor.contactFilter(editor.autocomplete.bcc.searchText)"
label:placeholder="Add a recipient">
<md-item-template>
<span class="md-contact-suggestion">
<span class="md-contact-name"
md-highlight-text="editor.autocomplete.to.searchText"
md-highlight-flags="^i">{{user.$$fullname}}</span>
<span class="md-contact-email"
md-highlight-text="editor.autocomplete.to.searchText"
md-highlight-flags="^i">{{user.$$email}}</span>
</span>
</md-item-template>
<span md-highlight-text="editor.autocomplete.bcc.searchText"
md-highlight-flags="^i">{{user}}</span>
</md-autocomplete>
<md-chip-template>{{$chip}}</md-chip-template>
</md-chips>
</div>
<!-- subject -->
<md-input-container>
<label>
<var:string label:value="Subject"/>
</label>
<input type="text" name="subject" ng-model="editor.message.editable.subject"/>
</md-input-container>
<md-list>
<!-- FILES ALREADY UPLOADED, FOR EXAMPLE WHEN WE FORWARD A
MAIL WITH ATTACHMENTS -->
<md-list-item ng-repeat="item in editor.message.editable.attachmentAttrs">
<div layout="row" layout-align="space-between center">
<span ng-bind="item.filename"><!-- filename --></span>
<md-button class="sg-icon-button"
ng-click="editor.message.$deleteAttachment(item.filename);">
<md-icon>remove_circle_outline</md-icon>
</md-button>
</div>
</md-list-item>
<!-- FILE BEING ATTACHED TO A MAIL -->
<md-list-item ng-repeat="item in editor.uploader.queue">
<div layout="row" layout-align="space-between center">
<span ng-bind="item.file.name"><!-- filename --></span>
<md-progress-linear md-mode="determinate"
value="{{item.progress}}"
ng-show="item.isUploading" ><!-- progress--></md-progress-linear>
<md-button class="sg-icon-button"
ng-click="editor.uploader.cancelItem(item)"
ng-show="item.isUploading">
<md-icon>cancel</md-icon>
</md-button>
<md-button class="sg-icon-button"
ng-click="editor.message.$deleteAttachment(item.file.name); item.remove();"
ng-show="!item.isUploading">
<md-icon>remove_circle_outline</md-icon>
</md-button>
</div>
</md-list-item>
</md-list>
</div>
<!-- toolbar to show cc/bcc/attachment fields -->
<div layout="column" layout-align="start end">
<md-button class="sg-icon-button " ng-show="editor.hideCc" ng-click="editor.hideCc = false">Cc</md-button>
<md-button class="sg-icon-button " ng-show="editor.hideBcc" ng-click="editor.hideBcc = false">Bcc</md-button>
<md-menu>
<md-button label:aria-label="More mail options" class="sg-icon-button" ng-click="$mdOpenMenu($event)">
<md-icon>more_vert</md-icon>
</md-button>
<md-menu-content width="4">
<md-menu-item>
<md-button ng-href="#">
<md-checkbox ng-model="editor.message.editable.receipt">
<var:string label:value="Return Receipt"/>
</md-checkbox>
</md-button>
</md-menu-item>
<md-menu-item>
<md-button class="md-primary" ng-disabled="true"><var:string label:value="Priority"/></md-button>
</md-menu-item>
<md-menu-item>
<md-button ng-click="editor.message.editable.priority = 1">
<md-icon ng-class="{ 'icon-check': editor.message.editable.priority == 1}"><!-- highest --></md-icon>
<var:string label:value="highest"/>
</md-button>
</md-menu-item>
<md-menu-item>
<md-button ng-click="editor.message.editable.priority = 2">
<md-icon ng-class="{ 'icon-check': editor.message.editable.priority == 2}"><!-- high --></md-icon>
<var:string label:value="high"/>
</md-button>
</md-menu-item>
<md-menu-item>
<md-button ng-click="editor.message.editable.priority = 3">
<md-icon ng-class="{ 'icon-check':
!editor.message.editable.priority
|| editor.message.editable.priority == 3}"><!-- normal --></md-icon>
<var:string label:value="normal"/>
</md-button>
</md-menu-item>
<md-menu-item>
<md-button ng-click="editor.message.editable.priority = 4">
<md-icon ng-class="{ 'icon-check': editor.message.editable.priority == 4}"><!-- low --></md-icon>
<var:string label:value="low"/>
</md-button>
</md-menu-item>
<md-menu-item>
<md-button ng-click="editor.message.editable.priority = 5">
<md-icon ng-class="{ 'icon-check': editor.message.editable.priority == 5}"><!-- lowest --></md-icon>
<var:string label:value="lowest"/>
</md-button>
</md-menu-item>
</md-menu-content>
</md-menu>
</div>
</header>
<!-- MESSAGE CONTENT -->
<textarea name="content" var:class="editorClass"
ck-locale="editor.localeCode"
ng-model="editor.message.editable.text"/>
</md-dialog-content>
<!-- TOOLBAR BUTTONS -->
<div class="md-actions">
<div layout="row" layout-align="space-between center" layout-fill="layout-fill">
<div>
<!-- md-icon does not play well with Firefox - makes the
file input never appear. This should eventually be
fixed in Angular Material -->
<label class="md-button" for="file-input">
<span><var:string label:value="Attach"/></span>
</label>
<input id="file-input" type="file"
nv-file-select="nv-file-select"
multiple="multiple"
uploader="editor.uploader"
ng-show="false"/>
<!-- TOOLBAR BUTTONS -->
<div class="buttonsToolbar">
<div layout="row" layout-align="end center">
<md-button ng-click="editor.cancel()"><var:string label:value="Cancel"/></md-button>
<md-button ng-click="editor.message.$save()"><var:string label:value="Save"/></md-button>
<md-button class="fg-sogoBlue-700 md-primary md-hue-3"
ng-click="editor.send()"><var:string label:value="Send"/></md-button>
</div>
</div>
<div>
<!-- FILES ALREADY UPLOADED, FOR EXAMPLE WHEN WE FORWARD A
MAIL WITH ATTACHMENTS -->
<md-chips ng-model="editor.message.editable.attachmentAttrs"
class="sg-readonly" readonly="true">
<md-chip-template>
<span>{{$chip.filename}}</span>
<md-icon ng-click="editor.message.$deleteAttachment($chip.filename);">close</md-icon>
</md-chip-template>
</md-chips>
<!-- FILE BEING ATTACHED TO A MAIL -->
<md-chips ng-model="editor.uploader.queue"
class="sg-readonly" readonly="true">
<md-chip-template>
<span>{{$chip.file.name}}</span>
<md-icon ng-show="!$chip.isUploading"
ng-click="editor.message.$deleteAttachment($chip.file.name);
$chip.remove();">close</md-icon>
<md-icon ng-show="$chip.isUploading"
ng-click="editor.uploader.cancelItem($chip)"
ng-style="{ 'color': '#F00' }">cancel</md-icon>
<span ng-show="$chip.isUploading">{{$chip.progress}} %</span>
</md-chip-template>
</md-chips>
</div>
</div>
</div>
</md-dialog>
</form>
</md-dialog-content>
</md-dialog>
</container>
+34 -43
View File
@@ -5,6 +5,7 @@
xmlns:label="OGo:label">
<div class="view-list" layout="column">
<md-content id="messagesList" layout="column" class="md-flex">
<md-progress-linear ng-show="mailbox.selectedFolder.$isLoading" md-mode="indeterminate"><!-- progress --></md-progress-linear>
<header class="sg-md-subheader sg-md-subheader--fixed">
<h2 class="md-default-theme sg-md-subhead-solo fg-sogoBlue-700">
<span ng-show="mailbox.selectedFolder.$messages.length > 0">{{mailbox.selectedFolder.$messages.length}} <var:string label:value="messages"/></span>
@@ -12,44 +13,39 @@
</h2>
</header>
<md-virtual-repeat-container class="md-flex">
<md-list class="sg-section-list">
<md-list-item
md-virtual-repeat="currentMessage in mailbox.selectedFolder"
md-on-demand="md-on-demand"
ng-class="{'sg-active': currentMessage.uid == mailbox.selectedFolder.selectedMessage, unread: !currentMessage.isread}"
ng-click="mailbox.selectMessage(currentMessage)"
ui-sref="mail.account.mailbox.message({accountId: mailbox.account.id, mailboxId: (mailbox.selectedFolder.path | encodeUri), messageId: currentMessage.uid})">
<!-- ui-sref-active="sg-active"> -->
<div class="sg-selected-avatar"
ng-show="currentMessage.selected"
ng-click="currentMessage.selected = !currentMessage.selected"><!-- selected avatar --></div>
<sg-avatar-image class="md-tile-left"
ng-show="!currentMessage.selected"
ng-click="currentMessage.selected = !currentMessage.selected"
sg-email="::currentMessage.from[0].email"
size="48"><!-- avatar --></sg-avatar-image>
<div class="sg-tile-content">
<span class="msg-date"
ng-bind-html="currentMessage.relativedate"><!-- date --></span>
<div class="sg-md-subhead-multi">{{currentMessage.$shortAddress('from')}}</div>
<div class="sg-md-body-multi">{{currentMessage.subject}}</div>
</div>
<div class="sg-tile-icons">
<md-icon ng-show="currentMessage.priority == 'highest' || currentMessage.priority == 'high'">warning</md-icon>
<md-icon ng-show="currentMessage.isflagged">star</md-icon>
<md-icon ng-show="currentMessage.isanswered">reply</md-icon>
<md-icon ng-show="currentMessage.isforwarded">forward</md-icon>
<md-icon ng-show="currentMessage.hasattachment">attach_file</md-icon>
</div>
</md-list-item>
<md-list>
<div md-virtual-repeat="currentMessage in mailbox.selectedFolder.$messages">
<md-list-item
ng-class="{'sg-active': currentMessage.uid == mailbox.selectedFolder.selectedMessage, unread: !currentMessage.isread}"
ng-click="mailbox.selectMessage(currentMessage)"
ui-sref="mail.account.mailbox.message({accountId: mailbox.account.id, mailboxId: (mailbox.selectedFolder.path | encodeUri), messageId: currentMessage.uid})">
<!-- ui-sref-active="sg-active"> -->
<div class="sg-selected-avatar"
ng-show="currentMessage.selected"
ng-click="currentMessage.selected = !currentMessage.selected"><!-- selected avatar --></div>
<sg-avatar-image class="md-tile-left"
ng-show="!currentMessage.selected"
ng-click="currentMessage.selected = !currentMessage.selected"
sg-email="currentMessage['from'][0].email"
size="48"><!-- avatar --></sg-avatar-image>
<div class="sg-tile-content">
<span class="msg-date"
ng-bind-html="currentMessage.relativedate"><!-- date --></span>
<div class="sg-md-subhead-multi">{{currentMessage.$shortAddress('from')}}</div>
<div class="sg-md-body-multi">{{currentMessage.subject}}</div>
<i class="icon-ion-refresh"
ng-hide="mailbox.selectedFolder.$loadMessage(currentMessage.uid)"><!-- loading --></i>
</div>
<div class="sg-tile-icons">
<md-icon ng-show="currentMessage.isflagged">star</md-icon>
<md-icon ng-show="currentMessage.isanswered">reply</md-icon>
<md-icon ng-show="currentMessage.isforwarded">forward</md-icon>
<md-icon ng-show="currentMessage.hasattachment">attach_file</md-icon>
</div>
</md-list-item>
</div>
</md-list>
</md-virtual-repeat-container>
<div class="sg-progress-circular-floating"
ng-show="mailbox.selectedFolder.$isLoading">
<md-progress-circular class="md-accent"
md-mode="indeterminate"
md-diameter="32"><!-- progress --></md-progress-circular>
</div>
<md-button class="md-fab md-fab-bottom-right md-accent"
label:aria-label="Write a new message"
ng-click="mailbox.newMessage($event)">
@@ -58,12 +54,7 @@
</md-content>
</div>
<md-content id="detailView" class="view-detail md-hue-1" layout="column" layout-align="center center"
ng-class="{ 'sg-close': !mailbox.selectedFolder.selectedMessage }"
ui-view="message">
<md-input-container class="hide-sm md-hue-1" style="flex-grow: 0">
<label class="sg-md-title"><var:string label:value="No message selected"/></label>
</md-input-container>
</md-content>
<div id="detailView" class="view-detail ng-cloak" layout="column" ui-view="message"
ng-show="mailbox.selectedFolder.selectedMessage"><!-- message view --></div>
</container>
+26 -28
View File
@@ -221,13 +221,13 @@
Templates script tag wrappers go next
-->
<main class="view layout-fill" ui-view="mailboxes" layout="row" ng-controller="navController"><!-- mailboxes list --></main>
<main class="view md-layout-fill" ui-view="mailboxes" layout="row" ng-controller="navController"><!-- mailboxes list --></main>
<!-- TEMPLATE SCRIPT WRAPPER -->
<script type="text/ng-template" id="UIxMailMainFrame">
<!-- Sidenav -->
<md-sidenav id="left-sidenav" class="md-sidenav-left md-whiteframe-z1 layout-fill" md-component-id="left" md-is-locked-open="isGtMedium" layout="column">
<md-sidenav id="left-sidenav" class="md-sidenav-left md-whiteframe-z1 md-layout-fill" md-component-id="left" md-is-locked-open="isGtMedium" layout="column">
<var:component className="UIxSidenavToolbarTemplate" />
<md-content md-scroll-y="md-scroll-y" class="md-flex">
<section ng-repeat="account in app.accounts track by account.id">
@@ -235,17 +235,17 @@
<div layout="row" layout-align="space-between center">
<span>{{account.name}}</span>
<div>
<md-button class="sg-icon-button"
label:aria-label="New Folder..."
ng-click="app.newFolder(account)">
<md-icon>add_circle_outline</md-icon>
</md-button>
<md-button class="sg-icon-button"
ng-show="account.id == 0"
label:aria-label="Delegation..."
ng-click="app.delegate(account)">
<md-icon>people</md-icon>
</md-button>
<md-button class="sg-icon-button"
label:aria-label="New Folder..."
ng-click="app.newFolder(account)">
<md-icon>add_circle_outline</md-icon>
</md-button>
<md-button class="sg-icon-button"
ng-show="account.id == 0"
label:aria-label="Delegation..."
ng-click="app.delegate(account)">
<md-icon>people</md-icon>
</md-button>
</div>
</div>
</md-subheader>
@@ -287,17 +287,12 @@
<var:string label:value="New Subfolder..."/>
</md-button>
</md-menu-item>
<md-menu-item ng-show="folder.$isEditable">
<md-button type="button" ng-click="app.editFolder(folder)">
<var:string label:value="Rename"/>
</md-button>
</md-menu-item>
<md-menu-item>
<md-button type="button" ng-click="app.compactFolder(folder)">
<var:string label:value="Compact"/>
</md-button>
</md-menu-item>
<md-menu-item ng-show="folder.$isEditable">
<md-menu-item ng-show="folder.$isEditable">
<md-button type="button" ng-click="app.confirmDelete(folder)">
<var:string label:value="Delete"/>
</md-button>
@@ -342,14 +337,18 @@
</md-content>
</md-sidenav>
<section layout="column" class="sg-app-content layout-fill" ui-view="mailbox"><!-- messages list --></section>
<section layout="column" class="sg-app-content md-layout-fill" ui-view="mailbox"><!-- messages list --></section>
</script>
<script type="text/ng-template" id="UIxMailFolderTemplate">
<md-toolbar layout="column" layout-align="space-between start" class="md-tall toolbar-main" >
<div class="md-toolbar-tools md-toolbar-tools-top"
layout="row" layout-align="space-between start">
<md-toolbar layout="column" layout-align="space-between start" class="md-tall toolbar-main">
<div class="md-toolbar-tools md-toolbar-tools-top sg-padded" layout="row" layout-align="space-between start">
<var:component className="UIxTopnavToolbarTemplate" />
<div class="sg-toolbar-group-last">
<md-button class="sg-icon-button" label:aria-label="More">
<md-icon>more_vert</md-icon>
</md-button>
</div>
</div>
<div class="md-toolbar-tools" layout="row" layout-align="space-between center"
ng-show="mailbox.selectedFolder.$selectedCount() == 0">
@@ -394,10 +393,9 @@
</md-button>
</md-menu-item>
<md-menu-divider> <!-- divider --></md-menu-divider>
<md-menu-item>
<md-button ng-href="#">
<md-menu-item >
<md-button ng-click="mailbox.selectedFolder.$filter()">
<md-checkbox
ng-change="mailbox.selectedFolder.$filter()"
ng-model="mailbox.service.$query.asc"
ng-true-value="0"
ng-false-value="1"><var:string label:value="Descending Order"/></md-checkbox>
@@ -474,12 +472,12 @@
</md-button>
<md-menu-content width="2">
<md-menu-item>
<md-button ng-click="mailbox.markSelectedMessagesAsFlagged()">
<md-button>
<var:string label:value="Flag"/>
</md-button>
</md-menu-item>
<md-menu-item>
<md-button ng-click="mailbox.markSelectedMessagesAsUnread()">
<md-button>
<var:string label:value="Mark as Unread"/>
</md-button>
</md-menu-item>
+7 -43
View File
@@ -20,18 +20,8 @@
<label class="pseudo-input-label">
<var:string label:value="From"/>
</label>
<div layout="row" layout-align="start center">
<sg-avatar-image class="md-tile-left"
sg-email="viewer.message.from[0].email"
size="48">
<!-- contact avatar -->
</sg-avatar-image>
<div class="md-list-item-text">
<span>{{ viewer.message.from[0].name }}</span><br/>
<a class="md-caption" href="#"
ng-bind="viewer.message.from[0].email"
ng-click="viewer.newMessage($event, viewer.message.from[0])"><!-- from --></a>
</div>
<div class="pseudo-input-field">
<a ng-href="mailto:{{viewer.message.from[0].email}}" ng-bind="viewer.message.from[0].full"><!-- from --></a>
</div>
</div>
@@ -39,26 +29,8 @@
<label class="pseudo-input-label">
<var:string label:value="To"/>
</label>
<div class="pseudo-input-field" ng-hide="viewer.message.$showDetailedRecipients">
<a href="#" ng-click="viewer.message.showDetailedRecipients()">{{viewer.message.$shortRecipients()}}</a>
</div>
<div class="pseudo-input-field" ng-show="viewer.message.$showDetailedRecipients">
<span ng-repeat="recipient in viewer.message.to">
<a href="#" ng-bind="recipient.full"
ng-click="viewer.newMessage($event, recipient)"><!-- recipient --></a>
</span>
</div>
</div>
<div class="pseudo-input-container--compact" ng-show="viewer.message.$showDetailedRecipients">
<label class="pseudo-input-label" ng-show="viewer.message.cc.length > 0">
<var:string label:value="Cc"/>
</label>
<div class="pseudo-input-field">
<span ng-repeat="recipient in viewer.message.cc">
<a href="#" ng-bind="recipient.full"
ng-click="viewer.newMessage($event, recipient)"><!-- recipient --></a>
</span>
<a ng-href="mailto:{{viewer.message.to[0].email}}" ng-bind="viewer.message.to[0].full"><!-- to --></a>
</div>
</div>
@@ -85,7 +57,7 @@
<div class="sg-icon-bar--vertical">
<md-button class="sg-icon-button show-sm"
label:aria-label="Close"
ng-click="viewer.close()">
ng-click="toggleDetailView()">
<md-icon>close</md-icon>
</md-button>
<!-- todo: Replace md-tooltip values by localizable string variable -->
@@ -130,12 +102,6 @@
<var:string label:value="Load Images"/>
</md-button>
</md-menu-item>
<md-menu-item>
<md-button label:aria-label="Save As..."
ng-click="viewer.saveMessage()">
<var:string label:value="Save As..."/>
</md-button>
</md-menu-item>
<md-menu-item>
<md-button label:aria-label="View Message Source"
ng-click="viewer.viewRawSource($event)">
@@ -170,11 +136,9 @@
<div class="msg-date sg-md-body-multi">
<time datetime="viewer.message.date" ng-bind="viewer.message.date"><!-- date --></time>
</div>
<div layout="row" layout-wrap="layout-wrap">
<div ng-class="part.msgclass" layout="row" layout-wrap="layout-wrap" class="mailer_mailcontent" ng-repeat="part in viewer.message.$content()">
<div ng-if="part.html" ng-bind-html="part.content"><!-- msg --></div>
<div ng-if="part.compile" sg-compile="part.content"><!-- msg --></div>
</div>
<div class="mailer_mailcontent" ng-repeat="part in viewer.message.$content()">
<div ng-if="part.html" ng-bind-html="part.content"><!-- msg --></div>
<div ng-if="part.compile" sg-compile="part.content"><!-- msg --></div>
</div>
</div>
</md-content>
+60 -29
View File
@@ -7,7 +7,7 @@
xmlns:const="http://www.skyrix.com/od/constant"
xmlns:rsrc="OGo:url"
xmlns:label="OGo:label"
const:jsFiles="Main.js, Common.js"
const:jsFiles="Main.app.js, Common.js"
>
<!--
MAIN CONTENT ROW
@@ -15,13 +15,32 @@
MUST be the first html element after body
SHOULD be a main tag (with role="main")
-->
<main class="view layout-fill layout-padding" ui-view="login" layout="row" layout-align="center start">
<main class="view md-layout-fill md-layout-padding" ui-view="login" layout="row" layout-align="center start">
<md-content class="md-padding" md-scroll-y="true">
<div class="sg-login" ng-controller="LoginController as app">
<div ng-controller="loginController">
<script type="text/javascript">
var cookieUsername = '<var:string var:value="cookieUsername" const:escapeHTML="NO"/>';
</script>
<!-- <div id="aboutBox" style="display:none;">
<div>
<p class="logo"><img const:alt="SOGo" rsrc:src="img/sogo-logo.png"/></p>
<p>Version <var:string value="version"/> <span class="buildDate">(<var:string value="buildDate" />)</span></p>
<p class="scroll"><var:string label:value="AboutBox" const:escapeHTML="NO"/></p>
<img const:alt="Inverse" rsrc:src="img/inverse.png"/>
<p class="links"><a href="http://sogo.nu/" target="_new">sogo.nu</a> /
<a href="http://inverse.ca/" target="_new">inverse.ca</a></p>
<p><a id="aboutClose" href="#" class="button">
<span><var:string label:value="OK" /></span></a></p>
</div>
</div> -->
<!-- <nav class="top-bar">
<section class="top-bar-section">
<ul class="right">
<li><a href="#"><var:string label:value="About" /></a></li>
</ul>
</section>
</nav> -->
<div id="login">
<div id="logo">
<img const:alt="*" id="splash" rsrc:src="img/sogo-full.svg"/>
@@ -29,22 +48,28 @@
<form name="loginForm" layout="column"
ng-cloak="ng-cloak"
ng-submit="app.login()">
ng-controller="loginController"
ng-submit="login(creds)">
<var:if condition="hasLoginSuffix">
<input type="hidden" ng-model="app.creds.loginSuffix" var:value="loginSuffix"/>
<input type="hidden" ng-model="creds.loginSuffix" var:value="loginSuffix"/>
</var:if>
<div ng-show="warning" ng-cloak="ng-cloak" alert="alert" class="alert-box radius warning">{{warning}}</div>
<md-input-container>
<md-icon>person</md-icon>
<input autocapitalize="off" type="text" ng-model="app.creds.username" ng-required="true" label:placeholder="Username"/>
<label>
<var:string label:value="Username"/>
</label>
<input autocapitalize="off" type="text" ng-model="creds.username" required="required" />
</md-input-container>
<md-input-container md-no-float="md-no-float">
<md-icon>email</md-icon>
<input type="password" ng-model="app.creds.password" ng-required="true" label:placeholder="Password"/>
<md-input-container>
<label>
<var:string label:value="Password"/>
</label>
<input type="password" ng-model="creds.password" required="required" />
</md-input-container>
<!-- CONNECT BUTTON -->
<div layout="row" layout-align="end center">
<md-button class="md-raised" type="submit" ng-disabled='app.loginForm.$invalid'>
<md-button class="md-raised" type="submit" ng-disabled='!loginForm.$valid'>
<span>
<var:string label:value="Connect"/>
</span>
@@ -53,32 +78,38 @@
<!-- LANGUAGES SELECT -->
<div layout="row" layout-align="start end">
<md-icon>language</md-icon>
<md-select flex="true" ng-model="app.creds.language" label:placeholder="choose">
<var:foreach list="languages" item="item">
<md-option var:value="item">
<var:string value="languageText"/>
</md-option>
</var:foreach>
<md-input-container>
<label class="login-lang">
<var:string label:value="Language"/>
</label>
<md-select flex="true" ng-model="creds.language">
<var:foreach list="languages" item="item">
<md-option var:value="item">
<var:string value="languageText"/>
</md-option>
</var:foreach>
</md-select>
</md-input-container>
</div>
<!-- DOMAINS SELECT -->
<var:if condition="hasLoginDomains">
<div layout="row" layout-align="start end">
<md-icon>domain</md-icon>
<md-select class="md-flex" ng-model="app.creds.domain" label:placeholder="choose">
<var:foreach list="loginDomains" item="item">
<md-option var:value="item">
<var:string value="item"/>
</md-option>
</var:foreach>
</md-select>
<label>
<var:string label:value="Domain"/>
</label>
<md-select flex="true" ng-model="creds.domain" label:placeholder="choose">
<var:foreach list="loginDomains" item="item">
<md-option var:value="item">
<var:string value="item"/>
</md-option>
</var:foreach>
</md-select>
</div>
</var:if>
<div layout="row" layout-align="center center">
<md-switch ng-model="app.creds.rememberLogin" label:arial-label="Remember username">
<md-switch ng-model="creds.rememberLogin" label:arial-label="Remember username">
<var:string label:value="Remember username"/>
</md-switch>
</div>
@@ -86,7 +117,7 @@
<div layout="row" layout-align="end end" ng-cloak="ng-cloak">
<md-button class="sg-icon-button fg-sogoPaper-500"
label:aria-label="About"
ng-click="app.showAbout()">
ng-click="showAbout()">
<md-icon class="material-icons fg-sogoPaper-500">info</md-icon>
</md-button>
</div>
@@ -105,7 +136,7 @@
<!--<img class="full-image" const:alt="Inverse" rsrc:src="img/inverse.png"/>-->
</md-dialog-content>
<div class="md-actions">
<md-button ng-click="about.closeDialog()"><var:string label:value="Close"/></md-button>
<md-button ng-click="closeDialog()"><var:string label:value="Close"/></md-button>
</div>
</md-dialog>
</script>
+35 -57
View File
@@ -9,98 +9,74 @@
xmlns:label="OGo:label"
className="UIxPageFrame"
>
<md-dialog flex="50" flex-sm="100">
<md-toolbar class="md-padding">
<div class="md-toolbar-tools">
<md-icon class="material-icons sg-icon-toolbar-bg">account_box</md-icon>
<md-input-container>
<label><var:string label:value="Account Name"/></label>
<input type="text" required="required"
ng-readonly="$AccountDialogController.accountId == 0"
ng-model="$AccountDialogController.account.name"/>
</md-input-container>
<md-button type="button" class="sg-icon-button " ng-click="$AccountDialogController.cancel()">
<md-icon>close</md-icon>
</md-button>
</div>
</md-toolbar>
<md-dialog>
<md-dialog-content>
<form id="mainForm" name="accountForm" var:href="ownPath">
<md-input-container>
<label><var:string label:value="Account Name"/></label>
<input type="text" required="required"
ng-readonly="accountId == 0" ng-model="account.name"/>
</md-input-container>
<md-input-container>
<label><var:string label:value="Server Name"/></label>
<input type="text" required="required"
ng-readonly="$AccountDialogController.accountId == 0"
ng-model="$AccountDialogController.account.serverName"/>
ng-readonly="accountId == 0" ng-model="account.serverName"/>
</md-input-container>
<md-input-container>
<label><var:string label:value="Port"/></label>
<input type="number" required="required" min="1" max="65535"
ng-readonly="$AccountDialogController.accountId == 0"
ng-model="$AccountDialogController.account.port"/>
ng-readonly="accountId == 0" ng-model="account.port"/>
</md-input-container>
<label><var:string label:value="Encryption"/></label>
<md-radio-group ng-model="$AccountDialogController.account.encryption">
<md-radio-button ng-disabled="$AccountDialogController.accountId == 0" value="none" class="md-primary"><var:string label:value="None"/></md-radio-button>
<md-radio-button ng-disabled="$AccountDialogController.accountId == 0" value="ssl"><var:string label:value="SSL"/></md-radio-button>
<md-radio-button ng-disabled="$AccountDialogController.accountId == 0" value="tls"><var:string label:value="TLS"/></md-radio-button>
<md-radio-group ng-model="account.encryption">
<md-radio-button ng-disabled="accountId == 0" value="none" class="md-primary"><var:string label:value="None"/></md-radio-button>
<md-radio-button ng-disabled="accountId == 0" value="ssl"><var:string label:value="SSL"/></md-radio-button>
<md-radio-button ng-disabled="accountId == 0" 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-readonly="$AccountDialogController.accountId == 0"
ng-model="$AccountDialogController.account.userName"/>
ng-readonly="accountId == 0" ng-model="account.userName"/>
</md-input-container>
<md-input-container>
<label><var:string label:value="Password"/></label>
<input type="password"
ng-readonly="$AccountDialogController.accountId == 0"
ng-model="$AccountDialogController.account.password"/>
<input type="password" ng-readonly="accountId == 0"
ng-model="account.password"/>
</md-input-container>
<md-input-container>
<label><var:string label:value="Full Name"/></label>
<input type="text" required="required"
ng-readonly="$AccountDialogController.customFromIsReadonly()"
ng-model="$AccountDialogController.account.identities[0].fullName"/>
ng-readonly="customFromIsReadonly()"
ng-model="account.identities[0].fullName"/>
</md-input-container>
<md-input-container>
<label><var:string label:value="Email"/></label>
<input type="email" required="required"
ng-readonly="$AccountDialogController.customFromIsReadonly()"
ng-model="$AccountDialogController.account.identities[0].email"/>
ng-readonly="customFromIsReadonly()"
ng-model="account.identities[0].email"/>
</md-input-container>
<md-input-container>
<label><var:string label:value="Reply To Email"/></label>
<input type="email" ng-model="$AccountDialogController.account.identities[0].replyTo"/>
<input type="email" ng-model="account.identities[0].replyTo"/>
</md-input-container>
<!-- To switch between a simple text editor and the CK/HTML editor, we use a ng-if and not
a ng-class as it doesn't get initialized by the ckEditor class directive -->
<md-input-container ng-if="$AccountDialogController.defaults.SOGoMailComposeMessageType == 'text'">
<label><var:string label:value="Signature"/> {{$AccountDialogController.defaults.SOGoMailComposeMessageType}}</label>
<textarea ng-model="$AccountDialogController.account.identities[0].signature"><!-- signature --></textarea>
</md-input-container>
<div class="pseudo-input-container"
ng-if="$AccountDialogController.defaults.SOGoMailComposeMessageType == 'html'">
<label class="pseudo-input-label"><var:string label:value="Signature"/> {{$AccountDialogController.defaults.LocaleCode}}</label>
<textarea class="ck-editor"
ck-locale="$AccountDialogController.defaults.LocaleCode"
ck-options="{ 'height': '70px',
'toolbar': [['Bold', 'Italic', '-', 'Link',
'Font','FontSize','-','TextColor',
'BGColor']] }"
ng-model="$AccountDialogController.account.identities[0].signature"><!-- signature --></textarea>
</div>
<!-- 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="$AccountDialogController.account.receipts.receiptAction">
<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>
@@ -108,7 +84,7 @@
<label>
<var:string label:value="If I'm not in the To or Cc of the message"/>
<md-select ng-model="$AccountDialogController.account.receipts.receiptNonRecipientAction">
<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>
@@ -117,7 +93,7 @@
<label>
<var:string label:value="If the sender is outside my domain"/>
<md-select ng-model="$AccountDialogController.account.receipts.receiptOutsideDomainAction">
<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>
@@ -126,18 +102,20 @@
<label>
<var:string label:value="In all other cases"/>
<md-select ng-model="$AccountDialogController.account.receipts.receiptAnyAction">
<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-disabled="accountForm.$invalid" ng-click="save()">Save</md-button>
</div>
</form>
</md-dialog-content>
<div class="md-actions">
<md-button ng-disabled="$AccountDialogController.accountForm.$invalid" ng-click="$AccountDialogController.save()"><var:string label:value="Save"/></md-button>
</div>
</md-dialog>
</var:component>
+62 -98
View File
@@ -7,31 +7,23 @@
xmlns:label="OGo:label"
xmlns:rsrc="OGo:url"
xmlns:uix="OGo:uix"><var:string var:value="doctype" const:escapeHTML="NO" />
<md-dialog flex="50" flex-sm="100">
<form id="mainForm" var:href="ownPath">
<md-toolbar class="md-padding">
<div class="md-toolbar-tools">
<md-icon class="material-icons sg-icon-toolbar-bg">filter_list</md-icon>
<md-input-container>
<label><var:string label:value="Filter name:"/></label>
<input class="md-title" type="text" ng-model="filter.name" required="required"/>
</md-input-container>
<md-button type="button" class="sg-icon-button " ng-click="cancel()">
<md-icon>close</md-icon>
</md-button>
</div>
</md-toolbar>
<md-dialog flex="50">
<md-dialog-content>
<script type="text/javascript">
var filterId = '<var:string value="filterId"/>';
var sieveFolderEncoding = '<var:string value="sieveFolderEncoding"/>';
var mailTags = <var:string value="labels" const:escapeHTML="NO"/>;
</script>
<div layout="row" layout-align="start center">
<div><var:string label:value="For incoming messages that"/></div>
<md-input-container class="md-flex">
<md-select ng-model="filter.match" required="required">
<form id="mainForm" var:href="ownPath">
<div id="filterNameContainer" class="container">
<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"/>
<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>
@@ -42,135 +34,107 @@
<var:string label:value="match all messages"/>
</md-option>
</md-select>
</md-input-container>
</div>
</div>
<!-- CONDITIONS -->
<div layout="column">
<div id="filterRules"><!-- empty -->
<md-list>
<md-list-item ng-repeat="rule in filter.rules">
<md-input-container flex="25">
<!-- CONDITIONS -->
<div id="filterRulesContainer" class="container">
<div id="filterRules"><!-- empty -->
<md-list>
<md-list-item ng-repeat="rule in filter.rules">
<md-select ng-model="rule.field">
<md-option ng-value="key" ng-repeat="(key, value) in fieldLabels">{{ value }}</md-option>
</md-select>
</md-input-container>
<md-input-container flex="25" ng-show="rule.field == 'header'">
<input type="text" ng-model="rule.custom_header"/>
</md-input-container>
<input type="text" ng-show="rule.field ==
'header'" ng-model="rule.custom_header"/>
<md-input-container flex="25" ng-show="rule.field == 'size'">
<md-select ng-model="rule.operator">
<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-input-container>
<md-input-container flex="25" ng-show="rule.field != 'size'">
<md-select ng-model="rule.operator">
<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>
</md-input-container>
<md-input-container class="md-flex">
<input type="text" ng-model="rule.value"/>
</md-input-container>
<md-button class="sg-icon-button" type="button"
ng-click="removeMailFilterRule($index)">
<md-icon>remove_circle</md-icon>
</md-button>
<md-button class="sg-icon-button" type="button"
ng-click="removeMailFilterRule($index)">
<md-icon>remove</md-icon>
</md-button>
</md-list-item>
</md-list>
</div>
</md-list-item>
</md-list>
</div>
<div layout="row" layout-align="end center">
<md-button class="sg-icon-button" type="button"
ng-click="addMailFilterRule($event)">
<md-icon>add_circle</md-icon>
<md-icon>add</md-icon>
</md-button>
</div>
</div>
<!-- ACTIONS -->
<div layout="column">
<var:string label:value="Perform these actions:"/>
<div id="filterActions"><!-- empty --></div>
<!-- ACTIONS -->
<div id="filterActionsContainer" class="container">
<var:string label:value="Perform these actions:"/><br/>
<div id="filterActions"><!-- empty --></div>
<md-list>
<md-list-item layout="row" layout-align="space-between center"
ng-repeat="action in filter.actions">
<md-input-container>
<md-list>
<md-list-item ng-repeat="action in filter.actions">
<md-select ng-model="action.method">
<md-option ng-value="key" ng-repeat="(key, value) in methodLabels">{{ value }}</md-option>
</md-select>
</md-input-container>
<!-- FORWARD MESSAGE TO -->
<md-input-container ng-show="action.method == 'redirect'" >
<input type="text" ng-model="action.argument"/>
</md-input-container>
<!-- FORWARD MESSAGE TO -->
<input type="text" ng-show="action.method == 'redirect'" ng-model="action.argument"/>
<!-- DISCARD -->
<!-- nada -->
<!-- DISCARD -->
<!-- nada -->
<!-- KEEP -->
<!-- nada -->
<!-- KEEP -->
<!-- nada -->
<!-- SEND REJECT MESSAGE -->
<md-input-container ng-show="action.method == 'reject'">
<input type="text" ng-model="action.argument"/>
</md-input-container>
<!-- SEND REJECT MESSAGE -->
<input type="text" ng-show="action.method == 'reject'" ng-model="action.argument"/>
<!-- FILE INTO -->
<md-input-container ng-show="action.method == 'fileinto'" >
<md-select 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>
</md-input-container>
<!-- FLAG WITH -->
<md-input-container ng-show="action.method == 'addflag'" >
<md-select ng-model="action.argument" >
<md-option value="seen"><var:string label:value="Seen"/></md-option>
<md-option value="deleted"><var:string label:value="Deleted"/></md-option>
<md-option value="answered"><var:string label:value="Answered"/></md-option>
<md-option value="flagged"><var:string label:value="Flagged"/></md-option>
<md-option value="junk"><var:string label:value="Junk"/></md-option>
<md-option value="not_junk"><var:string label:value="Not Junk"/></md-option>
<!-- 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>
</md-input-container>
<!-- STOP -->
<!-- nada -->
<!-- STOP -->
<!-- nada -->
<md-button class="sg-icon-button" type="button"
ng-click="removeMailFilterAction($index)">
<md-icon>remove_circle</md-icon>
</md-button>
<md-button class="sg-icon-button" type="button"
ng-click="removeMailFilterAction($index)">
<md-icon>remove</md-icon>
</md-button>
</md-list-item>
</md-list>
</md-list>
<div layout="row" layout-align="end center">
<md-button class="sg-icon-button" type="button"
ng-click="addMailFilterAction($event)">
<md-icon>add_circle</md-icon>
<md-icon>add</md-icon>
</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>
</md-dialog-content>
<div class="md-actions">
<md-button type="button" ng-click="save()"><var:string label:value="Save"/></md-button>
</div>
</form>
</form>
</md-dialog-content>
</md-dialog>
</container>
File diff suppressed because it is too large. Load diff
@@ -4,39 +4,33 @@
xmlns:var="http://www.skyrix.com/od/binding"
xmlns:const="http://www.skyrix.com/od/constant"
xmlns:label="OGo:label">
<md-dialog flex="60" flex-sm="100">
<md-dialog flex="60">
<form name="eventForm" ng-submit="editor.save(eventForm)">
<md-toolbar class="sg-padded" ng-class="editor.component.getClassName('bg')">
<md-toolbar class="md-padding" ng-class="editor.component.getClassName('bg')">
<div class="md-toolbar-tools">
<!-- summary -->
<md-icon ng-if="editor.component.classification == 'confidential'">visibility_off</md-icon>
<md-icon ng-if="editor.component.classification == 'private'">vpn_key</md-icon>
<md-input-container>
<label><var:string label:value="Title"/></label>
<md-input-container md-no-float="true">
<input type="text"
class="md-title"
ng-model="editor.component.summary"
required="required"/>
label:placeholder="Title"
ng-model="editor.component.summary"/>
</md-input-container>
<md-button class="md-icon-button" ng-click="editor.cancel()">
<md-icon aria-label="Close dialog">close</md-icon>
</md-button>
</div>
</md-toolbar>
<!--<md-chips>
<md-chip ng-repeat="category in editor.component.categories">{{category}}</md-chip>
</md-chips>-->
<md-dialog-content>
<!-- location -->
<md-input-container>
<label><var:string label:value="Location"/></label>
<input type="text" ng-model="editor.component.location"/>
</md-input-container>
<!-- calendar -->
<md-input-container>
<label><var:string label:value="Calendar"/></label>
<md-select ng-model="editor.component.destinationCalendar">
<md-option ng-repeat="calendar in ::editor.calendars"
ng-value="calendar.id">{{calendar.name}}</md-option>
</md-select>
</md-input-container>
<!-- categories -->
<md-chips ng-model="editor.component.categories">
<md-autocomplete
@@ -47,6 +41,14 @@
<span md-highlight-text="editor.categories.searchText">{{category}}</span>
</md-autocomplete>
</md-chips>
<!-- calendar -->
<md-input-container>
<label><var:string label:value="Calendar"/></label>
<md-select ng-model="editor.component.destinationCalendar">
<md-option ng-repeat="calendar in ::editor.calendars"
ng-value="calendar.id">{{calendar.name}}</md-option>
</md-select>
</md-input-container>
<!-- classification -->
<md-radio-group layout="row" layout-align="space-around center"
ng-model="editor.component.classification">
@@ -61,8 +63,8 @@
</md-radio-button>
</md-radio-group>
<!-- priority -->
<div class="pseudo-input-container">
<label class="pseudo-input-label"><var:string label:value="Priority"/></label>
<div layout="row" layout-align="center center">
<div flex="20"><var:string label:value="Priority"/></div>
<md-slider class="md-flex"
md-discrete="true"
ng-model="editor.component.priority"
@@ -96,17 +98,15 @@
<var:string label:value="Send Appointment Notifications"/>
</md-checkbox>
<!-- start + end -->
<div layout="column">
<div layout="row" layout-align="start center">
<span><var:string label:value="From"/></span>
<md-datepicker ng-model="editor.component.start"> <!-- date picker--></md-datepicker>
<sg-timepicker ng-model="editor.component.start"><!-- time picker --></sg-timepicker>
</div>
<div layout="row" layout-align="start center">
<span><var:string label:value="To"/></span>
<md-datepicker ng-model="editor.component.end"> <!-- date picker--></md-datepicker>
<sg-timepicker ng-model="editor.component.end"><!-- time picker --></sg-timepicker>
</div>
<div layout="row">
<md-input-container>
<label><var:string label:value="From"/></label>
<input type="text" ng-model="editor.component.startDate"/>
</md-input-container>
<md-input-container>
<label><var:string label:value="To"/></label>
<input type="text" ng-model="editor.component.endDate"/>
</md-input-container>
</div>
<!-- attach urls -->
<div class="attr" ng-repeat="attach in editor.component.attachUrls">
@@ -188,7 +188,7 @@
md-search-text="editor.searchText"
md-selected-item-change="editor.addAttendee(card)"
md-items="card in editor.cardFilter(editor.searchText)"
md-item-text="card.empty"
md-item-text="user.empty"
md-min-length="3"
md-delay="300"
md-no-cache="true"
@@ -243,8 +243,7 @@
<md-button type="button" ng-click="editor.component.$reset()">
<var:string label:value="Reset"/>
</md-button>
<md-button class="md-primary md-hue-3" type="submit"
ng-disabled="editor.eventForm.$invalid">
<md-button class="md-primary md-hue-3" type="submit">
<var:string label:value="Save"/>
</md-button>
</div>
@@ -144,7 +144,7 @@
class="md-flex"
md-input-name="delegatedTo"
md-search-text="editor.component.delegatedTo"
md-selected-item="cardToAdd"
md-selected-item="editor.cardToAdd"
md-items="card in editor.cardFilter(editor.component.delegatedTo)"
md-item-text="card.$$email"
md-min-length="3"
+24 -26
View File
@@ -18,30 +18,28 @@
<li><var:string label:value="Copy event to my calendar"/></li>
<li><var:string label:value="View Raw Source"/></li>
</ul>
</div>-->
<md-content>
<div layout="row" layout-align="center">
<h5>
<md-button
class="sg-icon-button"
label:aria-label="Previous Day"
var:date="prevDayQueryParameters.day"
ng-click="calendar.changeView($event)"><md-icon>chevron_left</md-icon></md-button>
<var:string value="currentDayName" />
<md-button
class="sg-icon-button"
label:aria-label="Next Day"
var:date="nextDayQueryParameters.day"
ng-click="calendar.changeView($event)"><md-icon>chevron_right</md-icon></md-button>
</h5>
</div>
<div id="calendarContent">
<var:component
className="UIxCalDayTable"
startDate="startDate"
const:CSSClass="dayOverview"
const:numberOfDays="1"
const:currentView="dayview"/>
</div>
</md-content>
</div>-->
<div layout="row" layout-align="center">
<h5>
<md-button
class="sg-icon-button"
label:aria-label="Previous Day"
var:date="prevDayQueryParameters.day"
ng-click="calendar.changeView($event)"><md-icon>chevron_left</md-icon></md-button>
<var:string value="currentDayName" />
<md-button
class="sg-icon-button"
label:aria-label="Next Day"
var:date="nextDayQueryParameters.day"
ng-click="calendar.changeView($event)"><md-icon>chevron_right</md-icon></md-button>
</h5>
</div>
<div id="calendarContent">
<var:component
className="UIxCalDayTable"
startDate="startDate"
const:CSSClass="dayOverview"
const:numberOfDays="1"
const:currentView="dayview"/>
</div>
</container>
+25 -50
View File
@@ -138,12 +138,15 @@
</div>
-->
<main class="view layout-fill" ui-view="calendars" layout="row" ng-controller="navController"><!-- calendars list --></main>
<main class="view md-layout-fill" ui-view="calendars" layout="row" ng-controller="navController"><!-- calendars list --></main>
<script type = "text/ng-template" id="UIxCalMainFrame">
<!-- calendars colors -->
<div sg-folder-stylesheet="true"
ng-repeat="calendar in calendars.service.$findAll()"
ng-repeat="calendar in calendars.service.$calendars"
ng-model="calendar"><!-- stylesheet --></div>
<div sg-folder-stylesheet="true"
ng-repeat="calendar in calendars.service.$subscriptions"
ng-model="calendar"><!-- stylesheet --></div>
<!-- Sidenav -->
<md-sidenav id="left-sidenav" class="md-sidenav-left md-whiteframe-z1" md-component-id="left" md-is-locked-open="isGtMedium" layout="column">
@@ -305,20 +308,18 @@
</md-sidenav>
<!-- Main section -->
<section layout="column" class="sg-app-content layout-fill"
<section layout="column" class="sg-app-content md-layout-fill"
ng-controller="CalendarListController as list">
<md-toolbar layout="column" layout-align="space-between start" class="md-tall toolbar-main">
<div class="md-toolbar-tools md-toolbar-tools-top" layout="row" layout-align="space-between start">
<var:component className="UIxTopnavToolbarTemplate" />
<!-- <div class="sg-toolbar-group-2">
<div class="md-toolbar-tools md-toolbar-tools-top sg-padded" layout="row" layout-align="space-between start">
<!-- <var:component className="UIxTopnavToolbarTemplate" /> -->
<div class="sg-toolbar-group-2">
<md-button class="sg-icon-button" label:aria-label="Search">
<md-icon>search</md-icon>
</md-button>
</div> -->
</div>
</div><!-- .md-toolbar-tools -->
<div class="md-toolbar-tools" layout="row"
layout-align="space-between center"
ng-show="list.component.$selectedCount() == 0">
<div class="md-toolbar-tools" layout="row" layout-align="space-between center">
<!-- sort/filter mode -->
<div class="view-list" layout="row" layout-align="space-between center"
ng-hide="list.mode.search">
@@ -474,18 +475,16 @@
</md-menu-item>
<md-menu-divider><!-- divider --></md-menu-divider>
<md-menu-item ng-if="list.componentType == 'events'">
<md-button ng-href="#">
<md-button ng-click="list.component.$filter(list.componentType)">
<md-checkbox
ng-change="list.component.$filter(list.componentType)"
ng-model="list.component.$queryEvents.asc"
ng-true-value="0"
ng-false-value="1"><var:string label:value="Descending Order"/></md-checkbox>
</md-button>
</md-menu-item>
<md-menu-item ng-if="list.componentType == 'tasks'">
<md-button ng-href="#">
<md-button ng-click="list.component.$filter(list.componentType)">
<md-checkbox
ng-change="list.component.$filter(list.componentType)"
ng-model="list.component.$queryTasks.asc"
ng-true-value="0"
ng-false-value="1"><var:string label:value="Descending Order"/></md-checkbox>
@@ -493,9 +492,6 @@
</md-menu-item>
</md-menu-content>
</md-menu>
<md-button class="sg-icon-button" ng-click="list.component.$filter(list.componentType)">
<md-icon>refresh</md-icon>
</md-button>
</div>
</div>
<!-- search mode -->
@@ -518,7 +514,7 @@
</md-input-container>
</div>
<!-- day/week/month views -->
<div>
<div class="sg-padded">
<a class="sg-icon-button md-button"
label:aria-label="Day"
href="#/calendar/day"><md-icon>view_day</md-icon></a>
@@ -530,19 +526,6 @@
href="#/calendar/month"><md-icon>view_module</md-icon></a>
</div>
</div>
<div layout="row" layout-align="start center" ng-show="list.component.$selectedCount() > 0">
<md-button class="sg-icon-button" ng-click="list.unselectComponents()">
<md-icon>arrow_back</md-icon>
</md-button>
<label>{{list.component.$selectedCount()}} selected</label>
<md-button class="sg-icon-button" ng-click="list.selectAll()">
<md-tooltip md-direction="left"><var:string label:value="Select All"/></md-tooltip>
<md-icon>select_all</md-icon>
</md-button>
<md-button class="sg-icon-button" ng-click="list.confirmDeleteSelectedComponents()">
<md-icon>delete</md-icon>
</md-button>
</div>
</md-toolbar>
<md-content layout="row" class="md-flex">
<md-content class="view-list md-flex" layout="column">
@@ -551,28 +534,24 @@
<!-- Events list -->
<md-tab label:label="Events"
md-on-select="list.selectComponentType('events')">
<md-list class="sg-section-list">
<md-list-item class="md-2-line"
<md-list>
<md-list-item class="md-clickable md-2-line"
ng-repeat="event in list.component.$events"
ng-click="list.openEvent($event, event)">
<div class="sg-selected-avatar" ng-show="event.selected"
ng-click="event.selected = !event.selected">
<!-- selected avatar -->
</div>
<i class="md-tile-left" ng-class="event.getClassName('bg')" ng-show="!event.selected" ng-click="event.selected = !event.selected"><!-- calendar color --></i>
<i class="md-avatar" ng-class="event.getClassName('bg')" ><!-- calendar color --></i>
<div class="md-list-item-text">
<h3>{{event.c_title}}</h3>
<p>{{event.c_location}}</p>
<p class="md-secondary" layout="row">
{{event.formatted_startdate}}
<i class="sg-tile-icons">
<span class="sg-tile-icons">
<md-icon ng-show="event.c_iscycle">repeat</md-icon>
<md-icon ng-show="event.c_nextalarm">alarm</md-icon>
</i>
</span>
</p>
</div>
</md-list-item>
<md-list-item disabled="disabled" ng-if="list.component.$events.length == 0">
<md-list-item ng-if="list.component.$events.length == 0">
<p class="sg-md-caption"><var:string label:value="No events for selected criteria"/></p>
</md-list-item>
</md-list>
@@ -580,15 +559,11 @@
<!-- Tasks list -->
<md-tab label:label="Tasks"
md-on-select="list.selectComponentType('tasks')">
<md-list class="sg-section-list">
<md-list-item class="md-2-line"
<md-list>
<md-list-item class="md-clickable md-2-line"
ng-repeat="task in list.component.$tasks"
ng-click="list.openTask($event, task)">
<div class="sg-selected-avatar" ng-show="task.selected"
ng-click="task.selected = !task.selected">
<!-- selected avatar -->
</div>
<i class="md-tile-left" ng-class="task.getClassName('bg')" ng-show="!task.selected" ng-click="task.selected = !task.selected"><!-- calendar color --></i>
<i class="md-avatar" ng-class="task.getClassName('bg')" ><!-- calendar color --></i>
<div class="md-list-item-text">
<h3>{{task.c_title}}</h3>
<p class="md-secondary" layout="row">
@@ -600,7 +575,7 @@
</p>
</div>
</md-list-item>
<md-list-item disabled="disabled" ng-if="list.component.$tasks.length == 0">
<md-list-item ng-if="list.component.$tasks.length == 0">
<p class="sg-md-caption"><var:string label:value="No tasks for selected criteria"/></p>
</md-list-item>
</md-list>
@@ -612,7 +587,7 @@
<md-icon>add</md-icon>
</md-button>
</md-content>
<div id="detailView" hide-sm="hide-sm" class="view-detail" layout="column" ui-view="calendarView"><!-- calendar view --></div>
<md-content class="view-detail sg-padded" ui-view="calendarView"><!-- calendar view --></md-content>
</md-content>
</section>
</script>
+19 -23
View File
@@ -21,22 +21,21 @@
</ul>
</div>
<md-content>
<div layout="row" layout-align="center">
<h5>
<md-button
class="sg-icon-button"
label:aria-label="Previous Month"
var:date="prevMonthQueryParameters.day"
ng-click="calendar.changeView($event)"><md-icon>chevron_left</md-icon></md-button>
<var:string value="monthNameOfThisMonth" />
<md-button
class="sg-icon-button"
label:aria-label="Next Month"
var:date="nextMonthQueryParameters.day"
ng-click="calendar.changeView($event)"><md-icon>chevron_right</md-icon></md-button>
</h5>
</div>
<div layout="row" layout-align="center">
<h5>
<md-button
class="sg-icon-button"
label:aria-label="Previous Month"
var:date="prevMonthQueryParameters.day"
ng-click="calendar.changeView($event)"><md-icon>chevron_left</md-icon></md-button>
<var:string value="monthNameOfThisMonth" />
<md-button
class="sg-icon-button"
label:aria-label="Next Month"
var:date="nextMonthQueryParameters.day"
ng-click="calendar.changeView($event)"><md-icon>chevron_right</md-icon></md-button>
</h5>
</div>
<div class="monthView">
<div layout="row" layout-align="center center">
<var:foreach list="headerDaysToDisplay" item="currentTableDay">
@@ -56,16 +55,13 @@
var:day-number="currentDayNumber"
var:id="currentDayId">
<div layout="column" layout-fill="true">
<div class="sg-calendar-tile-header"><var:string value="dayHeaderNumber"/></div>
<sg-calendar-month-day
sg-blocks="calendar.blocks"
sg-click="list.openEvent(event, component)"
var:sg-day="currentTableDay.shortDateString"><!-- day's events --></sg-calendar-month-day>
</div>
<div class="sg-calendar-tile-header"><var:string value="dayHeaderNumber"/></div>
<sg-calendar-month-day
sg-blocks="calendar.blocks"
var:sg-day="currentTableDay.shortDateString"><!-- day's events --></sg-calendar-month-day></div>
</md-grid-tile>
</var:foreach>
</var:foreach>
</md-grid-list>
</div>
</md-content>
</container>
+23 -25
View File
@@ -6,29 +6,27 @@
xmlns:rsrc="OGo:url"
xmlns:label="OGo:label">
<md-content>
<div layout="row" layout-align="center">
<h5>
<md-button
class="sg-icon-button"
label:aria-label="Previous Week"
var:date="prevWeekQueryParameters.day"
ng-click="calendar.changeView($event)"><md-icon>chevron_left</md-icon></md-button>
<var:string value="currentWeekName" />
<md-button
class="sg-icon-button"
label:aria-label="Next Week"
var:date="nextWeekQueryParameters.day"
ng-click="calendar.changeView($event)"><md-icon>chevron_right</md-icon></md-button>
</h5>
</div>
<div id="calendarContent">
<var:component
className="UIxCalDayTable"
startDate="startDate"
const:CSSClass="weekOverview"
const:numberOfDays="7"
const:currentView="weekview"/>
</div>
</md-content>
<div layout="row" layout-align="center">
<h5>
<md-button
class="sg-icon-button"
label:aria-label="Previous Week"
var:date="prevWeekQueryParameters.day"
ng-click="calendar.changeView($event)"><md-icon>chevron_left</md-icon></md-button>
<var:string value="currentWeekName" />
<md-button
class="sg-icon-button"
label:aria-label="Next Week"
var:date="nextWeekQueryParameters.day"
ng-click="calendar.changeView($event)"><md-icon>chevron_right</md-icon></md-button>
</h5>
</div>
<div id="calendarContent">
<var:component
className="UIxCalDayTable"
startDate="startDate"
const:CSSClass="weekOverview"
const:numberOfDays="7"
const:currentView="weekview"/>
</div>
</container>
@@ -7,15 +7,14 @@
xmlns:label="OGo:label"
>
<md-dialog flex="60" flex-sm="100">
<md-dialog flex="40">
<md-toolbar class="sg-padded">
<md-icon class="material-icons sg-icon-toolbar-bg">link</md-icon>
<div class="md-toolbar-tools">
<div class="pseudo-input-container md-flex">
<label class="pseudo-input-label"><var:string label:value="Links to this Calendar"/></label>
<div class="pseudo-input-field sg-md-title">{{links.calendar.name}}</div>
<div class="pseudo-input-field sg-md-title"><var:string value="calendar.displayName"/></div>
</div>
<md-button class="md-icon-button" ng-click="links.close()">
<md-button class="md-icon-button" ng-click="close()">
<md-icon label:aria-label="Close">close</md-icon>
</md-button>
</div>
@@ -25,45 +24,50 @@
<div layout="column" layout-padding="layout-padding">
<div layout="column" layout-padding="layout-padding">
<md-input-container ng-show="links.calendar.isWebCalendar">
<label><var:string label:value="URL"/></label>
<input type="text" ng-model="links.calendar.urls.webCalendarURL" ng-readonly="true"/>
</md-input-container>
<div ng-hide="links.calendar.isWebCalendar">
<var:if condition="isWebCalendar">
<md-input-container>
<label><var:string label:value="URL"/></label>
<input var:value="webCalendarURL" ng-readonly="true"/>
</md-input-container>
</var:if>
<var:if condition="isWebCalendar" const:negate="YES">
<div class="sg-md-title"><var:string label:value="Authenticated User Access"/></div>
<md-input-container>
<label><var:string label:value="CalDAV URL"/></label>
<input type="text" ng-model="links.calendar.urls.calDavURL" ng-readonly="true"/>
<input var:value="calDavURL" ng-readonly="true"/>
</md-input-container>
<md-input-container>
<label><var:string label:value="WebDAV ICS URL"/></label>
<input type="text" ng-model="links.calendar.urls.webDavICSURL" ng-readonly="true"/>
<input var:value="webDavICSURL" ng-readonly="true"/>
</md-input-container>
<md-input-container>
<label><var:string label:value="WebDAV XML URL"/></label>
<input type="text" ng-model="links.calendar.urls.webDavXMLURL" ng-readonly="true"/>
<input var:value="webDavXMLURL" ng-readonly="true"/>
</md-input-container>
</div>
</var:if>
</div>
<var:if condition="isPublicAccessEnabled">
<div layout="column" layout-padding="layout-padding" ng-hide="links.calendar.isWebCalendar">
<var:if condition="isWebCalendar" const:negate="YES">
<div layout="column" layout-padding="layout-padding">
<div class="sg-md-title"><var:string label:value="Public Access"/></div>
<md-input-container>
<label><var:string label:value="CalDAV URL"/></label>
<input type="text" ng-model="links.calendar.urls.publicCalDavURL" ng-readonly="true"/>
<input var:value="publicCalDavURL" ng-readonly="true"/>
</md-input-container>
<md-input-container>
<label><var:string label:value="WebDAV ICS URL"/></label>
<input type="text" ng-model="links.calendar.urls.publicWebDavICSURL" ng-readonly="true"/>
<input var:value="publicWebDavICSURL" ng-readonly="true"/>
</md-input-container>
<md-input-container>
<label><var:string label:value="WebDAV XML URL"/></label>
<input type="text" ng-model="links.calendar.urls.publicWebDavXMLURL" ng-readonly="true"/>
<input var:value="publicWebDavXMLURL" ng-readonly="true"/>
</md-input-container>
</div>
</var:if>
</var:if>
</div>
</md-dialog-content>
@@ -6,7 +6,7 @@
xmlns:const="http://www.skyrix.com/od/constant"
xmlns:label="OGo:label"
>
<md-dialog flex-sm="100">
<md-dialog>
<md-toolbar ng-style="{ 'background-color': properties.calendar.color }">
<div class="md-toolbar-tools sg-padded--right">
@@ -22,19 +22,15 @@
<md-input-container class="md-input-number">
<input type="number" label:aria-label="Every" ng-model="editor.component.repeat.interval"/>
</md-input-container>
<var:string label:value="Week(s)"/>
</div>
<div class="pseudo-input-container layout-padding" layout="row" layout-align="center center">
<label class="pseudo-input-label"><var:string label:value="On"/></label>
<md-grid-list md-cols="7" md-row-height="2em" md-gutter="0.5em"
flex="50" flex-md="80" flex-sm="100"
sg-toggle-grid="editor.component.repeat.days"
sg-toggle-grid-attr="day">
<var:foreach list="shortWeekDaysList" item="item">
<md-grid-tile var:value="valueForWeekDay"><var:string value="labelForWeekDay"/></md-grid-tile>
</var:foreach>
</md-grid-list>
<var:string label:value="Week(s)"/> <var:string label:value="On"/>
</div>
<md-grid-list md-cols="7" md-row-height="1:1" md-gutter="0.5em"
sg-toggle-grid="editor.component.repeat.days"
sg-toggle-grid-attr="day">
<var:foreach list="shortWeekDaysList" item="item">
<md-grid-tile var:value="valueForWeekDay"><var:string value="labelForWeekDay"/></md-grid-tile>
</var:foreach>
</md-grid-list>
</div>
<!-- monthly -->
@@ -50,43 +46,40 @@
<md-radio-button value="bymonthday">
<var:string label:value="Recur on day(s)"/>
</md-radio-button>
<div layout="row" layout-align="start center">
<md-grid-list md-cols="7" md-row-height="2em" md-gutter="0.5em"
flex="50" flex-md="80" flex-sm="100"
sg-toggle-grid="editor.component.repeat.monthdays">
<md-grid-tile value="1">1</md-grid-tile>
<md-grid-tile value="2">2</md-grid-tile>
<md-grid-tile value="3">3</md-grid-tile>
<md-grid-tile value="4">4</md-grid-tile>
<md-grid-tile value="5">5</md-grid-tile>
<md-grid-tile value="6">6</md-grid-tile>
<md-grid-tile value="7">7</md-grid-tile>
<md-grid-tile value="8">8</md-grid-tile>
<md-grid-tile value="9">9</md-grid-tile>
<md-grid-tile value="10">10</md-grid-tile>
<md-grid-tile value="11">11</md-grid-tile>
<md-grid-tile value="12">12</md-grid-tile>
<md-grid-tile value="13">13</md-grid-tile>
<md-grid-tile value="14">14</md-grid-tile>
<md-grid-tile value="15">15</md-grid-tile>
<md-grid-tile value="16">16</md-grid-tile>
<md-grid-tile value="17">17</md-grid-tile>
<md-grid-tile value="18">18</md-grid-tile>
<md-grid-tile value="19">19</md-grid-tile>
<md-grid-tile value="20">20</md-grid-tile>
<md-grid-tile value="21">21</md-grid-tile>
<md-grid-tile value="22">22</md-grid-tile>
<md-grid-tile value="23">23</md-grid-tile>
<md-grid-tile value="24">24</md-grid-tile>
<md-grid-tile value="25">25</md-grid-tile>
<md-grid-tile value="26">26</md-grid-tile>
<md-grid-tile value="27">27</md-grid-tile>
<md-grid-tile value="28">28</md-grid-tile>
<md-grid-tile value="29">29</md-grid-tile>
<md-grid-tile value="30">30</md-grid-tile>
<md-grid-tile value="31">31</md-grid-tile>
</md-grid-list>
</div>
<md-grid-list md-cols="7" md-row-height="1:1" md-gutter="0.5em"
sg-toggle-grid="editor.component.repeat.monthdays">
<md-grid-tile value="1">1</md-grid-tile>
<md-grid-tile value="2">2</md-grid-tile>
<md-grid-tile value="3">3</md-grid-tile>
<md-grid-tile value="4">4</md-grid-tile>
<md-grid-tile value="5">5</md-grid-tile>
<md-grid-tile value="6">6</md-grid-tile>
<md-grid-tile value="7">7</md-grid-tile>
<md-grid-tile value="8">8</md-grid-tile>
<md-grid-tile value="9">9</md-grid-tile>
<md-grid-tile value="10">10</md-grid-tile>
<md-grid-tile value="11">11</md-grid-tile>
<md-grid-tile value="12">12</md-grid-tile>
<md-grid-tile value="13">13</md-grid-tile>
<md-grid-tile value="14">14</md-grid-tile>
<md-grid-tile value="15">15</md-grid-tile>
<md-grid-tile value="16">16</md-grid-tile>
<md-grid-tile value="17">17</md-grid-tile>
<md-grid-tile value="18">18</md-grid-tile>
<md-grid-tile value="19">19</md-grid-tile>
<md-grid-tile value="20">20</md-grid-tile>
<md-grid-tile value="21">21</md-grid-tile>
<md-grid-tile value="22">22</md-grid-tile>
<md-grid-tile value="23">23</md-grid-tile>
<md-grid-tile value="24">24</md-grid-tile>
<md-grid-tile value="25">25</md-grid-tile>
<md-grid-tile value="26">26</md-grid-tile>
<md-grid-tile value="27">27</md-grid-tile>
<md-grid-tile value="28">28</md-grid-tile>
<md-grid-tile value="29">29</md-grid-tile>
<md-grid-tile value="30">30</md-grid-tile>
<md-grid-tile value="31">31</md-grid-tile>
</md-grid-list>
<div layout="row" layout-align="start center">
<md-radio-button value="byday">
<var:string label:value="The"/>
@@ -118,30 +111,27 @@
</md-input-container>
<var:string label:value="Year(s)"/>
</div>
<div layout="row" layout-align="start center">
<md-grid-list md-cols="6" md-row-height="2em" md-gutter="0.5em"
flex="50" flex-md="80" flex-sm="100"
sg-toggle-grid="editor.component.repeat.months">
<var:foreach list="yearlyMonthList" item="item">
<md-grid-tile var:value="valueForYearlyMonth"><var:string value="item"/></md-grid-tile>
</var:foreach>
</md-grid-list>
</div>
<div layout="row" layout-align="start center">
<md-checkbox ng-model="editor.component.repeat.year.byday">
<var:string label:value="The"/>
</md-checkbox>
<md-select ng-model="editor.component.repeat.month.occurrence">
<var:foreach list="monthlyRepeatList" item="item">
<md-option var:value="valueForMonthlyRepeat"><var:string value="itemText"/></md-option>
</var:foreach>
</md-select>
<md-select ng-model="editor.component.repeat.month.day">
<var:foreach list="yearlyDayList" item="item">
<md-option var:value="valueForYearlyDay"><var:string value="item"/></md-option>
</var:foreach>
</md-select>
</div>
<md-grid-list md-cols="6" md-row-height="1:1" md-gutter="0.5em"
sg-toggle-grid="editor.component.repeat.months">
<var:foreach list="yearlyMonthList" item="item">
<md-grid-tile var:value="valueForYearlyMonth"><var:string value="item"/></md-grid-tile>
</var:foreach>
</md-grid-list>
<div layout="row" layout-align="start center">
<md-checkbox ng-model="editor.component.repeat.year.byday">
<var:string label:value="The"/>
</md-checkbox>
<md-select ng-model="editor.component.repeat.month.occurrence">
<var:foreach list="monthlyRepeatList" item="item">
<md-option var:value="valueForMonthlyRepeat"><var:string value="itemText"/></md-option>
</var:foreach>
</md-select>
<md-select ng-model="editor.component.repeat.month.day">
<var:foreach list="yearlyDayList" item="item">
<md-option var:value="valueForYearlyDay"><var:string value="item"/></md-option>
</var:foreach>
</md-select>
</div>
</div>
</container>
@@ -4,7 +4,7 @@
xmlns:var="http://www.skyrix.com/od/binding"
xmlns:const="http://www.skyrix.com/od/constant"
xmlns:label="OGo:label">
<div layout="row" layout-align="start center" layout-wrap="layout-wrap">
<div layout="row" layout-align="start center">
<md-input-container class="md-input-number">
<input type="number" label:aria-label="quantity" ng-model="editor.component.alarm.quantity"/>
</md-input-container>
@@ -4,19 +4,18 @@
xmlns:var="http://www.skyrix.com/od/binding"
xmlns:const="http://www.skyrix.com/od/constant"
xmlns:label="OGo:label">
<md-dialog flex="60" flex-sm="100">
<md-dialog flex="60">
<form name="eventForm" ng-submit="editor.save(eventForm)">
<md-toolbar ng-class="editor.component.getClassName('bg')">
<div class="md-toolbar-tools sg-padded">
<md-toolbar class="md-padding" ng-class="editor.component.getClassName('bg')">
<div class="md-toolbar-tools">
<!-- summary -->
<md-icon ng-if="editor.component.classification == 'confidential'">visibility_off</md-icon>
<md-icon ng-if="editor.component.classification == 'private'">vpn_key</md-icon>
<md-input-container>
<label><var:string label:value="Title"/></label>
<md-input-container md-no-float="true">
<input type="text"
class="md-title"
ng-model="editor.component.summary"
required="required"/>
label:placeholder="Title"
ng-model="editor.component.summary"/>
</md-input-container>
<md-button class="md-icon-button" ng-click="editor.cancel()">
<md-icon aria-label="Close dialog">close</md-icon>
@@ -80,35 +79,15 @@
<var:string label:value="All day Event"/>
</md-checkbox>
<!-- start + end -->
<div class="section" layout="column">
<div layout="row" layout-align="start center" ng-show="editor.component.start">
<label><var:string label:value="From"/></label>
<md-datepicker ng-model="editor.component.start"> <!-- date picker--></md-datepicker>
<sg-timepicker ng-model="editor.component.start"><!-- time picker --></sg-timepicker>
<md-button class="sg-icon-button" type="button" ng-click="editor.component.$deleteStartDate()">
<md-icon>remove_circle</md-icon>
</md-button>
</div>
<div class="md-layout-margin" layout="row" layout-align="start center" ng-hide="editor.component.start">
<md-button class="sg-icon-button" type="button" ng-click="editor.component.$addStartDate()">
<md-icon>add_circle</md-icon>
</md-button>
<label class="button-label"><var:string label:value="Add From"/></label>
</div>
</div>
<div layout="row" layout-align="start center" ng-show="editor.component.due">
<label><var:string label:value="Due"/></label>
<md-datepicker ng-model="editor.component.due"> <!-- date picker--></md-datepicker>
<sg-timepicker ng-model="editor.component.due"><!-- time picker --></sg-timepicker>
<md-button class="sg-icon-button" type="button" ng-click="editor.component.$deleteDueDate()">
<md-icon>remove_circle</md-icon>
</md-button>
</div>
<div class="md-layout-margin" layout="row" layout-align="start center" ng-hide="editor.component.due">
<md-button class="sg-icon-button" type="button" ng-click="editor.component.$addDueDate()">
<md-icon>add_circle</md-icon>
</md-button>
<label class="button-label"><var:string label:value="Add Due"/></label>
<div layout="row">
<md-input-container>
<label><var:string label:value="Start"/></label>
<input type="text" ng-model="editor.component.startDate"/>
</md-input-container>
<md-input-container>
<label><var:string label:value="Due"/></label>
<input type="text" ng-model="editor.component.dueDate"/>
</md-input-container>
</div>
<!-- status -->
<div layout="row">
@@ -227,8 +206,7 @@
<md-button type="button" ng-click="editor.component.$reset()">
<var:string label:value="Reset"/>
</md-button>
<md-button class="md-primary md-hue-3" type="submit"
ng-disabled="editor.eventForm.$invalid">
<md-button class="md-primary md-hue-3" type="submit">
<var:string label:value="Save"/>
</md-button>
</div>
@@ -4,20 +4,20 @@
xmlns:var="http://www.skyrix.com/od/binding"
xmlns:const="http://www.skyrix.com/od/constant"
xmlns:label="OGo:label">
<md-dialog flex="40" flex-md="60" flex-sm="100">
<md-toolbar class="md-padding" ng-class="editor.component.getClassName('bg')">
<md-dialog flex="40">
<md-toolbar class="md-padding" ng-class="viewer.component.getClassName('bg')">
<div class="md-toolbar-tools">
<md-icon class="material-icons sg-icon-toolbar-bg">assignment_turned_in</md-icon>
<div class="sg-md-title md-flex">
<h2 class="md-flex">
<!-- classification -->
<md-icon ng-if="editor.component.classification == 'confidential'">visibility_off</md-icon>
<md-icon ng-if="editor.component.classification == 'private'">vpn_key</md-icon>
<md-icon ng-if="viewer.component.classification == 'confidential'">visibility_off</md-icon>
<md-icon ng-if="viewer.component.classification == 'private'">vpn_key</md-icon>
<!-- summary -->
{{editor.component.summary}}
{{viewer.component.summary}}
<!-- priority -->
<md-icon ng-repeat="i in editor.component.priority | range">star</md-icon>
</div>
<md-button class="md-icon-button" ng-click="editor.close()">
<md-icon ng-repeat="i in viewer.component.priority | range">star</md-icon>
</h2>
<md-button class="md-icon-button" ng-click="viewer.close()">
<md-icon aria-label="Close dialog">close</md-icon>
</md-button>
</div>
@@ -25,77 +25,77 @@
<md-dialog-content>
<md-list>
<!-- categories -->
<md-list-item ng-show="editor.component.categories.length > 0">
<md-chips class="sg-readonly" ng-model="editor.component.categories" readonly="true">
<md-list-item ng-show="viewer.component.categories.length > 0">
<md-chips ng-model="viewer.component.categories" readonly="true">
<md-chip-template>
<span>{{$chip}}</span>
</md-chip-template>
</md-chips>
</md-list-item>
<!-- location -->
<md-list-item ng-show="editor.component.location">
<md-list-item ng-show="viewer.component.location">
<md-icon>place</md-icon>
<p>{{editor.component.location}}</p>
<p>{{viewer.component.location}}</p>
</md-list-item>
<!-- calendar -->
<md-list-item>
<md-icon>event</md-icon>
<p>{{editor.component.calendar}}</p>
<p>{{viewer.component.calendar}}</p>
</md-list-item>
<!-- start/due dates -->
<md-list-item class="md-2-line">
<md-icon>access_time</md-icon>
<div layout="row" class="md-flex">
<div class="md-list-item-text" ng-show="editor.component.startDate">
<div class="md-list-item-text" ng-show="viewer.component.startDate">
<p><var:string label:value="Start"/></p>
<h3>
{{editor.component.localizedStartDate}}
<span ng-hide="editor.component.isAllDay"> {{editor.component.localizedStartTime}}</span>
{{viewer.component.localizedStartDate}}
<span ng-hide="viewer.component.isAllDay"> {{viewer.component.localizedStartTime}}</span>
</h3>
</div>
<div class="md-list-item-text" ng-show="editor.component.dueDate">
<div class="md-list-item-text" ng-show="viewer.component.dueDate">
<p><var:string label:value="Due Date"/></p>
<h3>
{{editor.component.localizedDueDate}}
<span ng-hide="editor.component.isAllDay">{{editor.component.localizedDueTime}}</span>
{{viewer.component.localizedDueDate}}
<span ng-hide="viewer.component.isAllDay">{{viewer.component.localizedDueTime}}</span>
</h3>
</div>
</div>
</md-list-item>
<!-- status -->
<md-list-item ng-show="editor.component.status == 'completed'">
<md-list-item ng-show="viewer.component.status == 'completed'">
<md-icon>check</md-icon>
<p>{{editor.component.localizedCompletedDate}} {{editor.component.localizedCompletedTime}}</p>
<p>{{viewer.component.localizedCompletedDate}} {{viewer.component.localizedCompletedTime}}</p>
</md-list-item>
<md-list-item ng-show="editor.component.enablePercentComplete()">
<md-list-item ng-show="viewer.component.enablePercentComplete()">
<md-icon>call_made</md-icon>
<p>{{editor.component.percentComplete}} %</p>
<p>{{viewer.component.percentComplete}} %</p>
</md-list-item>
<!-- attach urls -->
<md-list-item ng-repeat="url in editor.component.attachUrls">
<md-list-item ng-show="viewer.component.attachUrls.length > 0">
<md-icon>link</md-icon>
<p><a ng-href="url.value">{{url.value}}</a></p>
<p ng-repeat="url in viewer.component.attachUrls"><a ng-href="url.value">{{url.value}}</a></p>
</md-list-item>
<!-- comment -->
<md-list-item ng-show="editor.component.comment">
<md-list-item ng-show="viewer.component.comment">
<md-icon>mode_comment</md-icon>
<p>{{editor.component.comment}}</p>
<p>{{viewer.component.comment}}</p>
</md-list-item>
<!-- repeat -->
<md-list-item ng-show="editor.component.repeat">
<md-list-item ng-show="viewer.component.repeat">
<md-icon>repeat</md-icon>
<p><!-- editor.component.repeat.toString() --></p>
<p><!-- viewer.component.repeat.toString() --></p>
</md-list-item>
<!-- reminder -->
<md-list-item ng-show="editor.component.$hasAlarm">
<md-list-item ng-show="viewer.component.$hasAlarm">
<md-icon>alarm</md-icon>
<p><!-- editor.component.alarm.toString() --></p>
<p><!-- viewer.component.alarm.toString() --></p>
</md-list-item>
</md-list>
</md-dialog-content>
<!-- edit -->
<div class="md-actions" ng-show="editor.component.isEditable()">
<md-button ng-click="editor.edit()">
<div class="md-actions">
<md-button ng-click="viewer.edit()">
<var:string label:value="Edit"/>
</md-button>
</div>
+194 -78
View File
@@ -6,31 +6,38 @@
xmlns:var="http://www.skyrix.com/od/binding"
xmlns:const="http://www.skyrix.com/od/constant"
xmlns:rsrc="OGo:url"
xmlns:label="OGo:label">
xmlns:label="OGo:label"
>
<var:string var:value="doctype" const:escapeHTML="NO" />
<var:if condition="hideFrame" const:negate="YES">
<html const:xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" const:lang="en">
<var:if condition="hideFrame" const:negate="YES"
>
<html const:xmlns="http://www.w3.org/1999/xhtml"
xml:lang="en" const:lang="en">
<head>
<title>
<var:string value="title" />
</title>
<meta name="hideFrame" var:content="hideFrame" />
<meta name="description" content="SOGo Web Interface" />
<meta name="author" content="Inverse inc." />
<meta name="author" content="SKYRIX Software AG/Inverse inc." />
<meta name="robots" content="stop" />
<meta name="build" var:content="buildDate" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link href="mailto:support@inverse.ca" rev="made" />
<link rel="shortcut icon" var:href="siteFavicon" type="image/x-icon" />
<link type="text/css" rel="stylesheet" rsrc:href="css/styles.css" />
<var:if condition="hasPageSpecificCSS">
<link type="text/css" rel="stylesheet" var:href="pageCSSURL"/>
<var:if condition="hasPageSpecificCSS"
>
<link type="text/css" rel="stylesheet" var:href="pageCSSURL"
/>
</var:if>
<var:foreach list="additionalCSSFiles" item="item">
<link type="text/css" rel="stylesheet" var:href="item"/>
<var:foreach list="additionalCSSFiles" item="item"
>
<link type="text/css" rel="stylesheet" var:href="item"
/>
</var:foreach>
<var:if-ie const:lte="9">
<var:if-ie const:lte="9"
>
<link type="text/css" rel="stylesheet" rsrc:href="iefixes.css" />
<script type="text/javascript" rsrc:src="XMLHttpRequest.js"><!-- space --></script>
</var:if-ie>
@@ -42,26 +49,152 @@
<div id="popupFrame" style="display: none;">
<iframe width="100%" height="100%" src="/SOGo/loading"><!-- space --></iframe>
</div>
</var:if>
<var:if condition="shortUserNameForDisplay" const:value="anonymous" const:negate="YES">
<var:if condition="hasUserSettingsKeys">
</var:if
>
<var:if condition="shortUserNameForDisplay" const:value="anonymous"
const:negate="YES">
<var:if condition="hasUserSettingsKeys"
>
<script type="text/javascript">
var UserSettings =<var:string value="userSettings" const:escapeHTML="NO" />;
</script>
</script
>
</var:if>
<var:if condition="hasUserDefaultsKeys">
<script type="text/javascript">
var UserDefaults =<var:string value="userDefaults" const:escapeHTML="NO" />;
</script>
</var:if>
</var:if>
<var:if condition="isPopup" const:negate="YES">
<var:if condition="isUIxDebugEnabled"><!-- space --></var:if>
</script
>
</var:if
>
</var:if
>
<var:if condition="isPopup" const:negate="YES"
>
<var:if condition="isUIxDebugEnabled"
><!-- space --></var:if>
</var:if>
<!-- MAIN CONTENT ROW -->
<!-- MAIN CONTENT ROW -->
<var:component-content />
<!-- BOTTOM-SHEET -->
<script type="text/ng-template" id="bottomSheetTemplate.html">
<md-bottom-sheet class="md-list">
<md-list>
<var:if condition="shortUserNameForDisplay" const:value="anonymous" const:negate="YES">
<!-- CALENDAR -->
<var:if condition="userHasCalendarAccess">
<var:if condition="isCalendar">
<md-list-item>
<md-button class="md-list-item-content" ng-disabled="true">
<md-icon>event</md-icon>
<var:string label:value="Calendar"/>
</md-button>
</md-list-item>
</var:if>
<var:if condition="isCalendar" const:negate="YES">
<md-list-item>
<md-button class="md-list-item-content" var:href="relativeCalendarPath">
<md-icon>event</md-icon>
<var:string label:value="Calendar"/>
</md-button>
</md-list-item>
</var:if>
</var:if>
<!-- CONTACTS -->
<var:if condition="isContacts">
<md-list-item>
<md-button class="md-list-item-content" ng-disabled="true">
<md-icon>contacts</md-icon>
<var:string label:value="Address Book"/>
</md-button>
</md-list-item>
</var:if>
<var:if condition="isContacts" const:negate="YES">
<md-list-item>
<md-button class="md-list-item-content" var:href="relativeContactsPath">
<md-icon>contacts</md-icon>
<var:string label:value="Address Book"/>
</md-button>
</md-list-item>
</var:if>
<!-- MAIL -->
<var:if condition="userHasMailAccess">
<var:if condition="isMail">
<md-list-item>
<md-button class="md-list-item-content" ng-disabled="true">
<md-icon>email</md-icon>
<var:string label:value="Mail"/>
</md-button>
</md-list-item>
</var:if>
<var:if condition="isMail" const:negate="YES">
<md-list-item>
<md-button class="md-list-item-content" var:href="relativeMailPath">
<md-icon>email</md-icon>
<var:string label:value="Mail"/>
</md-button>
</md-list-item>
</var:if>
</var:if>
<!-- PREFERENCES -->
<var:if condition="isPreferences">
<md-list-item>
<md-button class="md-list-item-content" ng-disabled="true">
<md-icon>settings</md-icon>
<var:string label:value="Preferences"/>
</md-button>
</md-list-item>
</var:if>
<var:if condition="isPreferences" const:negate="YES">
<md-list-item>
<md-button class="md-list-item-content" var:ng-href="relativePreferencesPath">
<md-icon>settings</md-icon>
<var:string label:value="Preferences"/>
</md-button>
</md-list-item>
</var:if>
<!-- ADMINISTRATION -->
<var:if condition="isSuperUser">
<var:if condition="isAdministration">
<md-list-item>
<md-button class="md-list-item-content" ng-disabled="true">
<md-icon>settings_applications</md-icon>
<var:string label:value="Administration"/>
</md-button>
</md-list-item>
</var:if>
<var:if condition="isAdministration" const:negate="YES">
<md-list-item>
<md-button class="md-list-item-content" var:href="relativeAdministrationPath">
<md-icon>settings_applications</md-icon>
<var:string label:value="Administration"/>
</md-button>
</md-list-item>
</var:if>
</var:if>
<!-- DISCONNECT -->
<var:if condition="canLogoff">
<md-list-item>
<md-button class="md-list-item-content" var:ng-href="logoffPath">
<md-icon>settings_power</md-icon>
<var:string label:value="Disconnect"/>
</md-button>
</md-list-item>
</var:if>
</var:if>
</md-list>
</md-bottom-sheet>
</script>
<var:if condition="shortUserNameForDisplay" const:value="anonymous" const:negate="YES">
</var:if>
@@ -69,92 +202,75 @@
<script type="text/javascript">
var ApplicationBaseURL = '<var:string value="modulePath" />';
var ResourcesURL = '<var:string value="applicationPath" />.woa/WebServerResources';
var minimumSearchLength = <var:string value="minimumSearchLength" />;
<var:if condition="isSuperUser">
var IsSuperUser = true;
var minimumSearchLength =<var:string value="minimumSearchLength" />;
<var:if condition="isSuperUser"
>var IsSuperUser = true;
</var:if>
<var:if condition="isSuperUser" const:negate="YES">
var IsSuperUser = false;
<var:if condition="isSuperUser" const:negate="YES"
>var IsSuperUser = false;
</var:if>
<var:if condition="usesCASAuthentication">
var usesCASAuthentication = true;
<var:if condition="usesCASAuthentication"
>var usesCASAuthentication = true;
</var:if>
<var:if condition="usesCASAuthentication" const:negate="YES">
var usesCASAuthentication = false;
<var:if condition="usesCASAuthentication" const:negate="YES"
>var usesCASAuthentication = false;
</var:if>
<var:if condition="shortUserNameForDisplay" const:value="anonymous" const:negate="YES">
var UserFolderURL = '<var:string value="userFolderPath" const:escapeHTML="NO" />';
<var:if condition="shortUserNameForDisplay" const:value="anonymous"
const:negate="YES"
>var UserFolderURL = '<var:string value="userFolderPath" const:escapeHTML="NO" />';
var UserLogin = '<var:string value="shortUserNameForDisplay" const:escapeHTML="NO" />';
var UserIdentification = '<var:string value="userIdentification" const:escapeHTML="NO" />';
var UserEmail = '<var:string value="userEmail" const:escapeHTML="NO" />';
var UserLanguage = '<var:string value="userLanguage" const:escapeHTML="NO" />';
// Application paths
var UserCalendarPath = '';
<var:if condition="userHasCalendarAccess">
UserCalendarPath = '<var:string value="relativeCalendarPath" const:escapeHTML="NO" />';
</var:if>
var UserContactsPath = '<var:string value="relativeContactsPath" const:escapeHTML="NO" />';
var UserMailPath = '';
<var:if condition="userHasMailAccess">
UserMailPath = '<var:string value="relativeMailPath" const:escapeHTML="NO" />';
</var:if>
var UserPreferencesPath = '<var:string value="relativePreferencesPath" const:escapeHTML="NO" />';
<var:if condition="isSuperUser">
var UserAdministrationPath = '<var:string value="relativeAdministrationPath" const:escapeHTML="NO" />';
</var:if>
var UserLogoffPath = '';
<var:if condition="canLogoff">
UserLogoffPath = '<var:string value="logoffPath" const:escapeHTML="NO" />';
</var:if>
</var:if>
// This is the equivalent of an AJAX call to /SOGo/so/_UserLogin_/date
var currentDay = <var:string value="currentDayDescription" const:escapeHTML="NO"/>;
// This is the equivalent of an AJAX call to /SOGo/so/_UserLogin_/date
var currentDay = <var:string value="currentDayDescription" const:escapeHTML="NO"/>;
<var:string value="commonLocalizableStrings" const:escapeHTML="NO" />
<var:string value="productLocalizableStrings" const:escapeHTML="NO" />
</script>
<script type="text/javascript" rsrc:src="js/vendor/lodash.min.js"><!-- space --></script>
<script type="text/javascript" rsrc:src="js/vendor/angular.min.js"><!-- space --></script>
<script type="text/javascript" rsrc:src="js/vendor/angular-animate.min.js"><!-- space --></script>
<script type="text/javascript" rsrc:src="js/vendor/angular-sanitize.min.js"><!-- space --></script>
<script type="text/javascript" rsrc:src="js/vendor/angular-aria.min.js"><!-- space --></script>
<script type="text/javascript" rsrc:src="js/vendor/angular.js"><!-- space --></script>
<script type="text/javascript" rsrc:src="js/vendor/angular-animate.js"><!-- space --></script>
<script type="text/javascript" rsrc:src="js/vendor/angular-sanitize.js"><!-- space --></script>
<script type="text/javascript" rsrc:src="js/vendor/angular-aria.js"><!-- space --></script>
<script type="text/javascript" rsrc:src="js/vendor/angular-material.js"><!-- space --></script>
<script type="text/javascript" rsrc:src="js/vendor/angular-ui-router.min.js"><!-- space --></script>
<script type="text/javascript" rsrc:src="js/vendor/angular-ui-router.js"><!-- space --></script>
<script type="text/javascript" rsrc:src="js/Common/utils.js"><!-- space --></script>
<var:if condition="hasProductSpecificJavaScript">
<script type="text/javascript" var:src="productJavaScriptURL"><!-- space --></script>
<script type="text/javascript"
var:src="productJavaScriptURL"><!-- space --></script>
</var:if>
<var:if condition="hasPageSpecificJavaScript">
<script type="text/javascript" var:src="pageJavaScriptURL"><!-- space --></script>
<script type="text/javascript"
var:src="pageJavaScriptURL"><!-- space --></script>
</var:if>
<var:foreach list="additionalJSFiles" item="item">
<var:foreach list="additionalJSFiles" item="item"
>
<script type="text/javascript" var:src="item"><!-- space --></script>
</var:foreach>
<var:foreach list="systemAdditionalJSFiles" item="item">
<var:foreach list="systemAdditionalJSFiles" item="item"
>
<script type="text/javascript" var:src="item"><!-- space --></script>
</var:foreach>
</var:if>
<var:if condition="isCompatibleBrowser" const:negate="YES">
<var:component className="SOGoBrowsersPanel"/>
<var:if condition="isCompatibleBrowser" const:negate="YES"
>
<var:component className="SOGoBrowsersPanel"
/>
</var:if>
<noscript>
<div class="javascriptPopupBackground">
</div>
<div class="javascriptMessagePseudoWindow noJavascriptErrorMessage">
<var:string label:value="noJavascriptError"/>
<br/>
<br/>
<a class="button" var:href="page.context.uri">
<var:string label:value="noJavascriptRetry"/>
<var:string label:value="noJavascriptError"
/>
<br />
<br
/>
<a class="button" var:href="page.context.uri"
>
<var:string label:value="noJavascriptRetry"
/>
</a>
</div>
</noscript>
+23 -10
View File
@@ -3,14 +3,27 @@
xmlns="http://www.w3.org/1999/xhtml"
xmlns:var="http://www.skyrix.com/od/binding"
xmlns:const="http://www.skyrix.com/od/constant"
xmlns:label="OGo:label">
<md-toolbar class="md-tall sg-padded">
<div layout="column" layout-align="center start">
<sg-avatar-image class="md-tile-left"
sg-email="activeUser.email"
size="48"><!-- avatar --></sg-avatar-image>
<p class="sg-md-title">{{activeUser.identification}}</p>
<p class="md-caption">{{activeUser.email}}</p>
</div>
</md-toolbar>
xmlns:label="OGo:label"
>
<md-toolbar class="md-tall">
<div class="md-toolbar-tools sg-padded" layout="row" layout-align="start start">
<md-button class="sg-icon-button"
label:aria-label="Apps"
ng-click="openBottomSheet()">
<md-icon>apps</md-icon>
</md-button>
<span class="sg-logo"><!-- logo.svg --></span>
</div>
<div class="md-toolbar-tools sg-padded" layout="row">
<div layout="column">
<p class="sg-md-title">{{activeUser.identification}}</p>
<!--fixme: implement this with the proper model and actions -->
<!-- <md-select class="sg-logout" ng-model="accounts.options" var:placeholder="shortUserNameForDisplay">
<md-option var:value="relativePreferencesPath"><var:string label:value="Preferences"/></md-option>
<var:if condition="canLogoff"><md-option var:value="logoffPath"><var:string label:value="Disconnect" /></md-option></var:if>
</md-select> -->
</div>
</div>
</md-toolbar>
</container>
+3 -52
View File
@@ -3,68 +3,19 @@
xmlns="http://www.w3.org/1999/xhtml"
xmlns:var="http://www.skyrix.com/od/binding"
xmlns:const="http://www.skyrix.com/od/constant"
xmlns:label="OGo:label">
xmlns:label="OGo:label"
>
<div class="sg-toolbar-group-1" layout="row">
<md-button ng-click="toggleLeft()"
class="hide-gt-md sg-button-navicon sg-icon-button"
label:aria-label="Toggle Menu">
<md-icon>menu</md-icon>
</md-button>
<div class="sg-date-group sg-padded" layout="column" layout-align="space-between end">
<div class="sg-date-group" layout="column" layout-align="space-between end">
<p class="sg-day" ng-bind="currentDay.weekday"><!-- weekday --></p>
<p class="sg-month" ng-bind="currentDay.month"><!-- month --></p>
<p class="sg-year" ng-bind="currentDay.year"><!-- year --></p>
</div>
<p class="sg-md-display-3 sg-date-today" ng-bind="currentDay.day"><!-- day --></p>
</div>
<div class="sg-toolbar-group-last">
<md-menu layout-fill="layout-fill">
<md-button label:aria-label="Modules"
class="sg-icon-button" ng-click="$mdOpenMenu($event)">
<md-icon>apps</md-icon>
</md-button>
<md-menu-content width="8">
<div class="md-toolbar-tools sg-padded" layout="row"
layout-align="space-around start">
<md-button class="sg-icon-button"
ng-show="activeUser.path.calendar.length"
ng-disabled="baseURL.endsWith('/Calendar')"
ng-href="{{activeUser.path.calendar}}">
<md-icon>event</md-icon>
<md-tooltip><var:string label:value="Calendar"/></md-tooltip>
</md-button>
<md-button class="sg-icon-button"
ng-disabled="baseURL.endsWith('/Contacts')"
ng-href="{{activeUser.path.contacts}}">
<md-icon>contacts</md-icon>
<md-tooltip><var:string label:value="Address Book"/></md-tooltip>
</md-button>
<md-button class="sg-icon-button"
ng-show="activeUser.path.mail.length"
ng-disabled="baseURL.endsWith('/Mail')"
ng-href="{{activeUser.path.mail}}">
<md-icon>email</md-icon>
<md-tooltip><var:string label:value="Mail"/></md-tooltip>
</md-button>
<md-button class="sg-icon-button"
ng-disabled="baseURL.endsWith(activeUser.login)"
ng-href="{{activeUser.path.preferences}}">
<md-icon>settings</md-icon>
<md-tooltip><var:string label:value="Preferences"/></md-tooltip>
</md-button>
<md-button class="sg-icon-button" ng-show="activeUser.isSuperUser" ng-href="{{activeUser.path.administration}}">
<md-icon>settings_applications</md-icon>
<md-tooltip><var:string label:value="Administration"/></md-tooltip>
</md-button>
<md-button class="sg-icon-button" ng-show="activeUser.path.logoff.length" ng-href="{{activeUser.path.logoff}}">
<md-icon>settings_power</md-icon>
<md-tooltip><var:string label:value="Disconnect"/></md-tooltip>
</md-button>
</div>
</md-menu-content>
</md-menu>
</div>
</container>
+7 -10
View File
@@ -4,9 +4,7 @@ include ../common.make
WEBSERVER_RESOURCE_DIRS = css fonts img js
.DEFAULT_GOAL := all
dev:
build-static-files:
npm install --production
@if [ ! -e angular-material/src ]; then \
git submodule init; \
@@ -19,10 +17,9 @@ dev:
fi
grunt --stack build
all:
@echo "The 'all' target does nothing. Use 'make dev' to generate static files and 'make install' to install them."
all :: build-static-files
install:
install ::
@if [ -L "$(SOGO_WEBSERVERRESOURCESDIR)" ]; then \
echo "$(SOGO_WEBSERVERRESOURCESDIR) is a symbolic link (for development?). Installation skipped."; \
else \
@@ -30,13 +27,13 @@ install:
cp -r $(WEBSERVER_RESOURCE_DIRS) $(SOGO_WEBSERVERRESOURCESDIR)/; \
fi
check:
check ::
clean:
clean ::
distclean: clean
distclean :: clean
uninstall:
uninstall ::
@if [ -L "$(SOGO_WEBSERVERRESOURCESDIR)" ]; then \
echo "$(SOGO_WEBSERVERRESOURCESDIR) is a symbolic link (for development?). Uninstallation skipped."; \
else \
+6 -7
View File
@@ -1,15 +1,14 @@
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/Common/utils.js'],
'js/Main.js': ['js/Main/Main.app.js'],
'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.services.js': ['js/Scheduler/*.service.js'],
'js/Scheduler.js': ['js/Scheduler/Scheduler.app.js', 'js/Scheduler/*Controller.js', 'js/Scheduler/*.directive.js'],
'js/Scheduler.js': ['js/Scheduler.app.js', 'js/Scheduler/*Controller.js', 'js/Scheduler/*.directive.js'],
'js/Contacts.services.js': ['js/Contacts/*.service.js'],
'js/Contacts.js': ['js/Contacts/Contacts.app.js', 'js/Contacts/*Controller.js', 'js/Contacts/*.directive.js'],
'js/Mailer.services.js': ['js/Mailer/*.service.js', 'js/Mailer/*Controller.js'],
'js/Mailer.js': ['js/Mailer/Mailer.app.js', 'js/Mailer/*.directive.js'],
'js/Contacts.js': ['js/Contacts.app.js', 'js/Contacts/*Controller.js', 'js/Contacts/*.directive.js'],
'js/Mailer.services.js': ['js/Mailer/*.service.js'],
'js/Mailer.js': ['js/Mailer.app.js', 'js/Mailer/*Controller.js', 'js/Mailer/*.directive.js'],
'js/Preferences.services.js': ['js/Preferences/*.service.js'],
'js/Preferences.js': ['js/Preferences/Preferences.app.js', 'js/Preferences/*Controller.js']
'js/Preferences.js': ['js/Preferences.app.js', 'js/Preferences/*Controller.js']
};
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
+4 -4
View File
@@ -2,9 +2,9 @@
"name": "sogo-web",
"private": true,
"devDependencies": {
"angular": "1.4.x",
"angular-animate": "1.4.x",
"angular-sanitize": "1.4.x",
"angular": "1.3.x",
"angular-animate": "1.3.x",
"angular-sanitize": "1.3.x",
"angular-ui-router": "latest",
"angular-file-upload": "latest",
"angular-material": "master",
@@ -12,6 +12,6 @@
"breakpoint-sass": ">=2.4.2"
},
"resolutions": {
"angular": "1.4.x"
"angular": "1.3.x"
}
}
File diff suppressed because it is too large. Load diff
-1
View File
@@ -1 +0,0 @@
{"version":3,"sources":["../scss/components/_palette.scss","../scss/core/reset.scss","styles.css","../scss/core/angular.scss","../scss/styles.scss","../angular-material/src/core/style/structure.scss","../angular-material/src/core/style/mixins.scss","../scss/core/variables.scss","../scss/core/structure.scss","../angular-material/src/core/services/layout/layout.scss","../scss/core/layout.scss","../bower_components/breakpoint-sass/stylesheets/_breakpoint.scss","../angular-material/src/core/style/typography.scss","../scss/core/typography.scss","../scss/core/_functions.scss","../angular-material/src/components/autocomplete/autocomplete.scss","../scss/components/autocomplete/autocomplete.scss","../scss/components/backdrop/_extends.scss","../angular-material/src/components/backdrop/backdrop.scss","../scss/components/backdrop/backdrop.scss","../scss/components/button/_extends.scss","../angular-material/src/components/button/button.scss","../scss/components/button/button.scss","../scss/components/card/_extends.scss","../angular-material/src/components/card/card.scss","../scss/components/card/card.scss","../scss/components/checkbox/_extends.scss","../angular-material/src/components/checkbox/checkbox.scss","../scss/components/checkbox/checkbox.scss","../scss/components/chips/_extends.scss","../angular-material/src/components/chips/chips.scss","../scss/components/chips/chips.scss","../scss/components/content/_extends.scss","../angular-material/src/components/content/content.scss","../scss/components/content/content.scss","../scss/components/datepicker/_extends-calendar.scss","../angular-material/src/components/datepicker/calendar.scss","../scss/components/datepicker/_extends-datePicker.scss","../angular-material/src/components/datepicker/datePicker.scss","../scss/components/datepicker/datePicker.scss","../scss/components/dialog/_extends.scss","../angular-material/src/components/dialog/dialog.scss","../scss/components/dialog/dialog.scss","../scss/components/divider/_extends.scss","../angular-material/src/components/divider/divider.scss","../scss/components/fabSpeedDial/_extends.scss","../angular-material/src/components/fabSpeedDial/fabSpeedDial.scss","../angular-material/src/components/gridList/grid-list.scss","../scss/components/gridList/grid-list.scss","../scss/components/icon/_extends.scss","../angular-material/src/components/icon/icon.scss","../scss/components/icon/icon.scss","../scss/components/input/_extends.scss","../angular-material/src/components/input/input.scss","../scss/components/input/input.scss","../scss/components/list/_extends.scss","../angular-material/src/components/list/list.scss","../scss/components/list/list.scss","../scss/components/menu/_extends.scss","../angular-material/src/components/menu/menu.scss","../scss/components/progressCircular/_extends.scss","../angular-material/src/components/progressCircular/progress-circular.scss","../scss/components/progressCircular/progress-circular.scss","../scss/components/radioButton/_extends.scss","../angular-material/src/components/radioButton/radio-button.scss","../scss/components/select/_extends.scss","../angular-material/src/components/select/select.scss","../scss/components/select/select.scss","../scss/components/sidenav/_extends.scss","../angular-material/src/components/sidenav/sidenav.scss","../scss/components/sidenav/sidenav.scss","../scss/components/slider/_extends.scss","../angular-material/src/components/slider/slider.scss","../scss/components/sticky/_extends.scss","../angular-material/src/components/sticky/sticky.scss","../scss/components/subheader/_extends.scss","../angular-material/src/components/subheader/subheader.scss","../scss/components/subheader/subheader.scss","../scss/components/switch/_extends.scss","../angular-material/src/components/switch/switch.scss","../scss/components/tabs/_extends.scss","../angular-material/src/components/tabs/tabs.scss","../scss/components/toast/_extends.scss","../angular-material/src/components/toast/toast.scss","../scss/components/toolbar/_extends.scss","../angular-material/src/components/toolbar/toolbar.scss","../scss/components/toolbar/toolbar.scss","../scss/components/tooltip/_extends.scss","../angular-material/src/components/tooltip/tooltip.scss","../scss/components/virtualRepeat/_extends.scss","../angular-material/src/components/virtualRepeat/virtual-repeater.scss","../scss/components/virtualRepeat/virtual-repeat.scss","../scss/components/whiteframe/_extends.scss","../angular-material/src/components/whiteframe/whiteframe.scss","../scss/components/timepicker/timepicker.scss","../scss/components/pseudo-input/pseudo-input.scss","../scss/views/LoginUI.scss","../scss/views/MailerUI.scss","../scss/views/ContactsUI.scss","../scss/views/MessageEditorUI.scss","../scss/views/SchedulerUI.scss","../scss/views/_view.scss","../scss/core/base_styles/_base_style.scss"],"names":[],"mappings":"AAEA;;;;;GAKG;AAqYiC;EAE9B,eAzSO,EAwSP;;AAEA;EAEA,0BA5SO,EA2SP;;AAJ8B;EAE9B,eAxSO,EAuSP;;AAEA;EAEA,0BA3SO,EA0SP;;AAJ8B;EAE9B,eAvSOLine truncated
-3
View File
@@ -1,3 +0,0 @@
function l(){var key=arguments[0],value=key;labels[key]?value=labels[key]:clabels[key]&&(value=clabels[key]);for(var i=1,j=0;i<arguments.length;i++,j++)value=value.replace("%{"+j+"}",arguments[i]);return value}!function(){"use strict";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"}),$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"})}angular.module("SOGo.Common",["ngMaterial"]).value("sgSettings",{baseURL:function(){return ApplicationBaseURL||null},activeUser:function(param){var settings={login:UserLogin||null,identification:UserIdentification||null,email:UserEmail||null,language:UserLanguage||null,folderURL:UserFolderURL||null,isSuperUser:IsSuperUser||null,path:{calendar:UserCalendarPath||null,contacts:UserContactsPath||null,mail:UserMailPath||null,preferences:UserPreferencesPath||null,administration:IsSuperUser?UserAdministrationPath:null,logoff:UserLogoffPath||null}};return param?settings[param]:settings}}).constant("sgColors",{selection:["#FFFFFF","#330033","#C0C0C0","#999999","#666666","#333333","#000000","#FFCCCC","#FF6666","#FF0000","#CC0000","#990000","#660000","#330000","#FFCC99","#FF9966","#FF9900","#FF6600","#CC6600","#993300","#663300","#FFFF99","#FFFF66","#FFCC66","#FFCC33","#CC9933","#996633","#663333","#FFFFCC","#FFFF33","#FFFF00","#FFCC00","#999900","#666600","#333300","#CCCCCC","#66FF99","#33FF33","#33CC00","#009900","#006600","#003300","#99FFFF","#33FFFF","#66CCCC","#00CCCC","#339999","#336666","#003333","#CCFFFF","#66FFFF","#33CCFF","#3366FF","#3333FF","#000099","#000066","#CCCCFF","#9999FF","#6666CC","#6633FF","#6600CC","#333399","#330099","#FFCCFF","#FF99FF","#CC66CC","#CC33CC","#993399","#663366","#99FF99"]}).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(){"use strict";function decodeUri($window){return $window.decodeURIComponent}decodeUri.$inject=["$window"],angular.module("SOGo.Common").filter("decodeUri",decodeUri)}(),function(){"use strict";function encodeUri($window){return $window.encodeURIComponent}encodeUri.$inject=["$window"],angular.module("SOGo.Common").filter("encodeUri",encodeUri)}(),function(){"use strict";function loc(){return l}angular.module("SOGo.Common").filter("loc",loc)}(),function(){"use strict";function range(){return function(n){for(var res=[],i=0;i<parseInt(n);i++)res.push(i);return res}}angular.module("SOGo.Common").filter("range",range)}(),function(){"use strict";function AclController($mdDialog,Dialog,usersWithACL,User,folder){function userFilter($query){return User.$filter($query,folder.$acl.users)}function closeModal(){folder.$acl.$resetUsersRights(),$mdDialog.hide()}function saveModal(){folder.$acl.$saveUsersRights().then(function(){$mdDialog.hide()},function(data,status){Dialog.alert(l("Warning"),l("An error occured please try again."))})}function confirmChange(user){var confirmation=user.$confirmRights();confirmation&&(vm.confirmation.showing=!0,vm.confirmation.message=confirmation)}function removeUser(user){folder.$acl.$removeUser(user.uid)["catch"](function(data,status){Dialog.alert(l("Warning"),l("An error occured please try again."))})}function addUser(data){data&&folder.$acl.$addUser(data).then(function(){vm.userToAdd="",vm.searchText=""},function(error){Dialog.alert(l("Warning"),error)})}function selectUser(user){vm.selectedUser==user?vm.selectedUser=null:(vm.selectedUser=user,vm.selectedUser.$rights())}var vm=this;vm.users=usersWithACL,vm.folder=folder,vm.selectedUser=null,vm.userToAdd="",vm.searchText="",vm.userFilter=userFilter,Line truncated
return{template:'<div class="sg-time-pane"><div class="hours-pane"><div ng-repeat="hoursBigLine in hours" layout="row" layout-sm="column" ><div ng-repeat="hoursLine in hoursBigLine" layout="row" class="hours" ><div flex layout="row" layout-align="center center" ng-repeat="hour in hoursLine"><md-button class="hourBtn md-fab md-mini" id="{{hour.id}}" ng-click="hourClickHandler(hour.displayName)">{{hour.displayName}}</md-button></div></div></div></div><div ng-repeat="minutesLine in min5" layout="row" class="min5" ng-show="is5min()"><div flex layout="row" layout-align="center center" ng-repeat="minute in minutesLine"><md-button class="minuteBtn md-fab md-mini" id="{{minute.id}}" ng-click="minuteClickHandler(minute.displayName)">{{minute.displayName}}</md-button></div></div><div ng-repeat="minutesLine in min1" layout="row" class="min1" ng-hide="is5min()"><div flex layout="row" layout-align="center center" ng-repeat="minute in minutesLine"><md-button class="minuteBtn md-fab md-mini" id="{{minute.id}}" ng-click="minuteClickHandler(minute.displayName)">{{minute.displayName}}</md-button></div></div><div flex layout="row" layout-align="center center" class="toggle-pane"><md-button class="toggleBtn md-fab md-mini" ng-bind="getToggleBtnLbl()" ng-click="toggleManual5min()"></md-button></div></div>',scope:{},require:["ngModel","sgTimePane"],controller:TimePaneCtrl,controllerAs:"ctrl",bindToController:!0,link:function(scope,element,attrs,controllers){var ngModelCtrl=controllers[0],sgTimePaneCtrl=controllers[1];console.log(element);var timePaneElement=element;sgTimePaneCtrl.configureNgModel(ngModelCtrl,sgTimePaneCtrl,timePaneElement)}}}function TimePaneCtrl($element,$attrs,$scope,$animate,$q,$mdConstant,$mdTheming,$$mdDateUtil,$mdDateLocale,$mdInkRipple,$mdUtil){var m;this.$scope=$scope,this.$element=$element,this.timePaneElement=$element[0].querySelector(".sg-time-pane"),this.$animate=$animate,this.$q=$q,this.$mdInkRipple=$mdInkRipple,this.$mdUtil=$mdUtil,this.keyCode=$mdConstant.KEY_CODE,this.dateUtil=$$mdDateUtil,this.id=nextTimePaneUniqueId++,this.ngModelCtrl=null,this.selectedTime=null,this.displayTime=null,this.isInitialized=!1,$scope.hours=[],$scope.hours[0]=[],$scope.hours[0][0]=[],$scope.hours[0][1]=[],$scope.hours[1]=[],$scope.hours[1][0]=[],$scope.hours[1][1]=[];for(var i=0;6>i;i++)$scope.hours[0][0][i]={id:"tp-"+this.id+"-hour-"+i,displayName:10>i?"0"+i:""+i,selected:!1},$scope.hours[0][1][i]={id:"tp-"+this.id+"-hour-"+(i+6),displayName:10>i+6?"0"+(i+6):""+(i+6),selected:!1},$scope.hours[1][0][i]={id:"tp-"+this.id+"-hour-"+(i+12),displayName:""+(i+12),selected:!1},$scope.hours[1][1][i]={id:"tp-"+this.id+"-hour-"+(i+18),displayName:""+(i+18),selected:!1};for($scope.min5=[],$scope.min5[0]=[],$scope.min5[1]=[],i=0;6>i;i++)m=5*i,$scope.min5[0][i]={id:"tp-"+this.id+"-minute5-"+m,displayName:10>m?":0"+m:":"+m,selected:!0},$scope.min5[1][i]={id:"tp-"+this.id+"-minute5-"+(m+30),displayName:":"+(m+30),selected:!1};for($scope.min1=[],i=0;12>i;i++){$scope.min1[i]=[];for(var ii=0;5>ii;ii++)m=5*i+ii,$scope.min1[i][ii]={id:"tp-"+this.id+"-minute-"+m,displayName:10>m?":0"+m:":"+m,selected:!0}}$scope.show5min=!0,$scope.getToggleBtnLbl=function(){return $scope.is5min()?">>":"<<"},$scope.toggleManual5min=function(){$scope.manual5min=!$scope.is5min()},$scope.is5min=function(){return $scope.manual5min===!0||$scope.manual5min===!1?$scope.manual5min:$scope.show5min},$attrs.tabindex||$element.attr("tabindex","-1");var self=this;this.hourClickHandler=function(displayVal){var updated=new Date(self.displayTime).setHours(Number(displayVal));self.setNgModelValue(updated,"hours")},$scope.hourClickHandler=this.hourClickHandler,this.minuteClickHandler=function(displayVal){var val=displayVal.substr(1),updated=new Date(self.displayTime).setMinutes(Number(val));self.setNgModelValue(updated,"minutes")},$scope.minuteClickHandler=this.minuteClickHandler,this.attachTimePaneEventListeners()}angular.module("SOGo.Common").directive("sgTimePane",timePaneDirective);var SELECTED_TIME_CLASS2="md-primary",FOCUSED_TIME_CLASS="md-focus",nextTimePaneUniqueId=0;TimePaneCtrl.$inject=["$element","$attrs","$scope","$animate","$q","$mdConstant","$mdTheming","$$mdDateUtil","$mdDateLocale","$mdInkRipple","$mdUtil"],TimePaneCtrl.prototype.configureNgModel=function(ngModelCtrl,sgTimePaneCtrl,timePaneElement){this.ngModelCtrl=ngModelCtrl;var self=this;ngModelCtrl.$render=function(){self.changeSelectedTime(self.ngModelCtrl.$viewValue,sgTimePaneCtrl,timePaneElement)}},TimePaneCtrl.prototype.changeSelectedTime=function(date,sgTimePaneCtrl,timePaneElement){var previousSelectedTime=this.selectedTime;this.selectedTime=new Date(date),this.changeDisplayTime(date).then(function(){if(previousSelectedTime){var prevH=previousSelectedTime.getHours(),prevHCell=document.getElementById("tp-"+sgTimePaneCtrl.id+"-hour-"+prevH);prevHCell&&(prevHCell.classList.remove(SELECTED_TIME_CLASS2),prevHCell.setAttribute("aria-selected","false"));var prevM=previousSelectedTime.getMinutes(),prevMCeLine truncated
//# sourceMappingURL=Common.js.map
-1
View File
@@ -1 +0,0 @@
{"version":3,"file":"Common.js","sources":["Common/utils.js","Common/Common.app.js","Common/decodeUri.filter.js","Common/encodeUri.filter.js","Common/loc.filter.js","Common/range.filter.js","Common/AclController.js","Common/navController.js","Common/Acl.service.js","Common/Alarm.service.js","Common/Authentication.service.js","Common/Dialog.service.js","Common/Gravatar.service.js","Common/Resource.service.js","Common/User.service.js","Common/sgFocus.service.js","Common/sgAvatarImage.directive.js","Common/sgColorPicker.directive.js","Common/sgCompile.directive.js","Common/sgEnter.directive.js","Common/sgEscape.directive.js","Common/sgFocus.directive.js","Common/sgFolderStylesheet.directive.js","Common/sgSearch.directive.js","Common/sgSubscribe.directive.js","Common/sgTarget.directive.js","Common/sgTimepicker.directive.js","Common/sgToggleGrid.directive.js"],"names":["l","key","arguments","value","labels","clabels","i","j","length","replace","configure","$mdThemingProvider","definePalette","50","100","200","300","400","500","600","700","800","900","A100","A200","A400","A700","contrastDefaultColor","contrastDarkColors","contrastLightColors","1000","theme","primaryPalette","default","hue-1","hue-2","hue-3","accentPalette","backgroundPalette","angular","module","baseURL","ApplicationBaseURL","activeUser","param","settings","login","UserLogin","identification","UserIdentification","email","UserEmail","language","UserLanguage","folderURL","UserFolderURL","isSuperUser","IsSuperUser","path","calendar","UserCalendarPath","contacts","UserContactsPath","mail","UserMailPath","preferences","UserPreferencesPath","administration","UserAdministrationPath","logoff","UserLogoffPath","constant","selection","sm","gt-sm","md","gt-md","lg","gt-lg","config","$inject","decodeUri","$window","decodeURIComponent","filter","encodeUri","encodeURIComponent","loc","range","n","res","parseInt","push","AclController","$mdDialog","Dialog","usersWithACL","User","folder","userFilter","$query","$filter","$acl","users","closeModal","$resetUsersRights","hide","saveModal","$saveUsersRights","then","data","status","alert","confirmChange","user","confirmation","$confirmRights","vm","showing","message","removeUser","$removeUser","uid","addUser","$addUser","userToAdd","searchText","error","selectUser","selectedUser","$rights","this","controller","navController","$scope","$timeout","$interval","$http","$mdSidenav","$mdBottomSheet","$mdMedia","$log","sgConstant","sgSettings","Alarm","currentDay","window","get","success","secondsBeforeTomorrow","toggleLeft","toggle","debug","toggleRight","openBottomSheet","show","parent","element","document","getElementById","templateUrl","toggleDetailView","detail","toggleClass","$watch","newVal","isGtMedium","getAlarms","Acl","folderId","factory","$q","Settings","Resource","extend","$$resource","$User","prototype","$users","_this","deferred","defer","resolve","promise","fetch","response","forEach","canSubscribeUser","isSubscribed","wasSubscribed","bind","_","indexOf","pluck","userClass","isGroup","reject","splice","$resetRights","deferredSave","deferredSubscribe","action","$rightsAreDirty","$omit","save","$shadowRights","copy","rights","uids","join","all","currentAlarm","AlarmService","$mdToast","$toast","now","Date","browserTime","Math","floor","getTime","alarms","sort","a","b","x","y","next","pop","utc","url","alarmTime","delay","f","showAlarm","cancel","AlarmController","scope","reminder","ok","position","hideDelay","template","summary","locals","Authentication","readCookie","name","foundCookie","prefix","pairs","currentPair","start","cookie","split","charAt","substr","readLoginCookie","loginValues","base64decode","redirectUrl","username","domain","userName","address","baseAddress","altBaseAddress","parts","hostpart","protocol","newAddress","location","href","startsWith","endsWith","getService","passwordPolicyConfig","service","d","password","rememberLogin","loginSuffix","method","loginCookie","expire","grace","msg","perr","LDAPPasswordPolicyError","PolicyNoError","PolicyAccountLocked","changePassword","newPassword","PolicyPasswordModNotAllowed","PolicyInsufficientPasswordQuality","PolicyPasswordTooShort","PolicyPasswordTooYoung","PolicyPasswordInHistory","formatted","PolicyPasswordUnknown","PolicyPasswordSystemUnknown","$get","PolicyPasswordChangeUnsupported","PolicyPasswordExpired","PolicyChangeAfterReset","PolicyMustSupplyOldPassword","provider","DialogService","$modal","title","content","confirm","options","prompt","label","PromptDialogController","o","body","clickOutsideToClose","escapeToClose","inputType","Gravatar","size","hash","s","substring","md5","_http","_q","_path","_activeUser","$factory","userResource","compact","escape","params","flatten","newguid","create","post","id","newValue","remove","userData","init","$gravatar","search","excludedUsers","when","results","index","compareUids","find","each","isUndefined","$$shortFormat","$shortFormat","$$image","image","c_email","empty","fullname","cn","no_email"Line truncated
@@ -48,7 +48,7 @@
else {
return Acl.$$resource.fetch(this.folderId, 'acls').then(function(response) {
_this.users = [];
//console.debug(JSON.stringify(users, undefined, 2));
// console.debug(JSON.stringify(users, undefined, 2));
angular.forEach(response.users, function(data) {
user = new Acl.$User(data);
user.canSubscribeUser = user.isSubscribed;
@@ -78,7 +78,7 @@
}
}
angular
.module('SOGo.Common')
.controller('AclController', AclController);
angular
.module('SOGo.Common')
.controller('AclController', AclController);
})();
@@ -58,67 +58,66 @@
Alarm.showAlarm = function(url) {
var _this = this;
this.$$resource.fetch(url, '?resetAlarm=yes').then(function(data) {
_this.$toast.show({
position: 'top right',
hideDelay: 0,
template: [
'<md-toast>',
' <md-input-container>',
' <label style="color: white;">' + data.summary + '</label>',
' <md-select ng-model="reminder">',
' <md-option value=5>',
l('5 minutes'),
' </md-option>',
' <md-option value=10>',
l('10 minutes'),
' </md-option>',
' <md-option value=15>',
l('15 minutes'),
' </md-option>',
' <md-option value=30>',
l('30 minutes'),
' </md-option>',
' <md-option value=45>',
l('45 minutes'),
' </md-option>',
' <md-option value=60>',
l('1 hour'),
' </md-option>',
' <md-option value=1440>',
l('1 day'),
' </md-option>',
' </md-select>',
' </md-input-container>',
' <md-button ng-click="cancel()">',
l('Cancel'),
' </md-button>',
' <md-button ng-click="ok()">',
l('Ok'),
' </md-button>',
'</md-toast>'
].join(''),
locals: {
url: url
},
controller: AlarmController
});
this.$$resource.fetch(url, '?resetAlarm=yes');
/**
* @ngInject
*/
AlarmController.$inject = ['scope', '$mdToast', 'url'];
function AlarmController(scope, $mdToast, url) {
scope.reminder = '10';
scope.cancel = function() {
$mdToast.hide();
};
scope.ok = function() {
_this.$$resource.fetch(url, 'view?snoozeAlarm=' + scope.reminder);
$mdToast.hide();
};
}
this.$toast.show({
position: 'top right',
hideDelay: 0,
template: [
'<md-toast>',
' <md-input-container>',
' <md-select ng-model="reminder">',
' <md-option value=5>',
l('5 minutes'),
' </md-option>',
' <md-option value=10>',
l('10 minutes'),
' </md-option>',
' <md-option value=15>',
l('15 minutes'),
' </md-option>',
' <md-option value=30>',
l('30 minutes'),
' </md-option>',
' <md-option value=45>',
l('45 minutes'),
' </md-option>',
' <md-option value=60>',
l('1 hour'),
' </md-option>',
' <md-option value=1440>',
l('1 day'),
' </md-option>',
' </md-select>',
' </md-input-container>',
' <md-button ng-click="cancel()">',
l('Cancel'),
' </md-button>',
' <md-button ng-click="ok()">',
l('Ok'),
' </md-button>',
'</md-toast>'
].join(''),
locals: {
url: url
},
controller: AlarmController
});
/**
* @ngInject
*/
AlarmController.$inject = ['scope', '$mdToast', 'url'];
function AlarmController(scope, $mdToast, url) {
scope.reminder = '10';
scope.cancel = function() {
$mdToast.hide();
};
scope.ok = function() {
_this.$$resource.fetch(url, 'view?snoozeAlarm=' + scope.reminder);
$mdToast.hide();
};
}
};
/**
@@ -26,6 +26,9 @@
// TODO: convert to a Factory recipe?
.provider('Authentication', Authentication);
/**
* @ngInject
*/
function Authentication() {
function readCookie(name) {
var foundCookie, prefix, pairs, i, currentPair, start;
@@ -88,11 +91,9 @@
this.$get = getService;
/**
* @ngInject
*/
getService.$inject = ['$q', '$http', 'passwordPolicyConfig'];
function getService($q, $http, passwordPolicyConfig) {
var _this = this, service;
service = {
+1 -10
View File
@@ -12,18 +12,9 @@
var settings = {
login: UserLogin || null,
identification: UserIdentification || null,
email: UserEmail || null,
language: UserLanguage || null,
folderURL: UserFolderURL || null,
isSuperUser: IsSuperUser || null,
path: {
calendar: UserCalendarPath || null,
contacts: UserContactsPath || null,
mail: UserMailPath || null,
preferences: UserPreferencesPath || null,
administration: (IsSuperUser ? UserAdministrationPath : null),
logoff: UserLogoffPath || null
}
isSuperUser: IsSuperUser || null
};
if (param)
return settings[param];
@@ -31,12 +31,12 @@
* @param {string} content
* @returns a promise that resolves if the user has clicked on the 'OK' button
*/
Dialog.confirm = function(title, content, options) {
Dialog.confirm = function(title, content) {
var confirm = this.$modal.confirm()
.title(title)
.content(content)
.ok((options && options.ok)? options.ok : l('OK'))
.cancel((options && options.cancel)? options.cancel : l('Cancel'));
.ok(l('OK'))
.cancel(l('Cancel'));
return this.$modal.show(confirm);
};
@@ -12,16 +12,10 @@
*/
function Gravatar() {
return function(email, size) {
var x, y, hash, s = size;
var hash, s = size;
if (!email) {
return '';
}
x = email.indexOf('<');
if (x >= 0) {
y = email.indexOf('>', x);
if (y > x)
email = email.substring(x+1,y);
}
if (!size) {
s = 48; // default to 48 pixels
}
@@ -45,7 +45,6 @@
*/
User.$filter = function(search, excludedUsers) {
var param = {search: search};
var _this = this;
if (!search) {
// No query specified
@@ -61,7 +60,7 @@
return User.$$resource.fetch(null, 'usersSearch', param).then(function(response) {
var results, index, user,
compareUids = function(data) {
return _this.uid == data.uid;
return this.uid == data.uid;
};
if (excludedUsers) {
// Remove excluded users from response
@@ -13,7 +13,6 @@
function navController($scope, $timeout, $interval, $http, $mdSidenav, $mdBottomSheet, $mdMedia, $log, sgConstant, sgSettings, Alarm) {
$scope.activeUser = sgSettings.activeUser();
$scope.baseURL = sgSettings.baseURL();
// Show current day in top bar
$scope.currentDay = window.currentDay;
@@ -1,743 +0,0 @@
(function() {
'use strict';
angular
.module('SOGo.Common')
.directive('sgTimePane', timePaneDirective);
function timePaneDirective() {
return {
template:
'<div class="sg-time-pane">' +
'<div class="hours-pane"><div ng-repeat="hoursBigLine in hours" layout="row" layout-sm="column" ><div ng-repeat="hoursLine in hoursBigLine" layout="row" class="hours" >' +
'<div flex layout="row" layout-align="center center" ng-repeat="hour in hoursLine">' +
'<md-button class="hourBtn md-fab md-mini" id="{{hour.id}}" ng-click="hourClickHandler(hour.displayName)">{{hour.displayName}}</md-button>'+
'</div></div></div></div>' +
'<div ng-repeat="minutesLine in min5" layout="row" class="min5" ng-show="is5min()">' +
'<div flex layout="row" layout-align="center center" ng-repeat="minute in minutesLine">' +
'<md-button class="minuteBtn md-fab md-mini" id="{{minute.id}}" ng-click="minuteClickHandler(minute.displayName)">{{minute.displayName}}</md-button>'+
'</div></div>' +
'<div ng-repeat="minutesLine in min1" layout="row" class="min1" ng-hide="is5min()">' +
'<div flex layout="row" layout-align="center center" ng-repeat="minute in minutesLine">' +
'<md-button class="minuteBtn md-fab md-mini" id="{{minute.id}}" ng-click="minuteClickHandler(minute.displayName)">{{minute.displayName}}</md-button>' +
'</div></div>' +
'<div flex layout="row" layout-align="center center" class="toggle-pane"><md-button class="toggleBtn md-fab md-mini" ng-bind="getToggleBtnLbl()" ng-click="toggleManual5min()"></md-button></div></div>',
scope: {},
require: ['ngModel', 'sgTimePane'],
controller: TimePaneCtrl,
controllerAs: 'ctrl',
bindToController: true,
link: function(scope, element, attrs, controllers) {
var ngModelCtrl = controllers[0];
var sgTimePaneCtrl = controllers[1];
console.log(element);
var timePaneElement = element;
sgTimePaneCtrl.configureNgModel(ngModelCtrl,sgTimePaneCtrl, timePaneElement);
}
};
}
/** Class applied to the selected hour or minute cell/. */
//var SELECTED_TIME_CLASS = 'md-calendar-selected-date';
//var SELECTED_TIME_CLASS1 = 'md-raised';
var SELECTED_TIME_CLASS2 = 'md-primary';
/** Class applied to the focused hour or minute cell/. */
var FOCUSED_TIME_CLASS = 'md-focus';
/** Next identifier for calendar instance. */
var nextTimePaneUniqueId = 0;
function TimePaneCtrl($element, $attrs, $scope, $animate, $q, $mdConstant,
$mdTheming, $$mdDateUtil, $mdDateLocale, $mdInkRipple, $mdUtil) {
var m;
this.$scope = $scope;
this.$element = $element;
this.timePaneElement = $element[0].querySelector('.sg-time-pane');
this.$animate = $animate;
this.$q = $q;
this.$mdInkRipple = $mdInkRipple;
this.$mdUtil = $mdUtil;
this.keyCode = $mdConstant.KEY_CODE;
this.dateUtil = $$mdDateUtil;
this.id = nextTimePaneUniqueId++;
this.ngModelCtrl = null;
this.selectedTime = null;
this.displayTime = null;
this.isInitialized = false;
$scope.hours=[];
$scope.hours[0]=[];
$scope.hours[0][0]=[];
$scope.hours[0][1]=[];
$scope.hours[1]=[];
$scope.hours[1][0]=[];
$scope.hours[1][1]=[];
for(var i=0; i<6; i++){
$scope.hours[0][0][i] = {id:'tp-'+this.id+'-hour-'+i, displayName:i<10?"0"+i:""+i, selected:false};
$scope.hours[0][1][i] = {id:'tp-'+this.id+'-hour-'+(i+6),displayName:(i+6)<10?"0"+(i+6):""+(i+6), selected:false};
$scope.hours[1][0][i] = {id:'tp-'+this.id+'-hour-'+(i+12), displayName:""+(i+12), selected:false};
$scope.hours[1][1][i] = {id:'tp-'+this.id+'-hour-'+(i+18), displayName:""+(i+18), selected:false};
}
$scope.min5=[];
$scope.min5[0]=[];
$scope.min5[1]=[];
for(i=0; i<6; i++){
m=i*5;
$scope.min5[0][i] = {id:'tp-'+this.id+'-minute5-'+m, displayName:m<10?":0"+m:":"+m, selected:true};
$scope.min5[1][i] = {id:'tp-'+this.id+'-minute5-'+(m+30), displayName:":"+(m+30), selected:false};
}
$scope.min1=[];
for(i=0; i<12; i++){
$scope.min1[i]=[];
for(var ii=0; ii<5; ii++){
m=i*5 + ii;
$scope.min1[i][ii] = {id:'tp-'+this.id+'-minute-'+m, displayName:m<10?":0"+m:":"+m, selected:true};
}
}
$scope.show5min=true;
$scope.getToggleBtnLbl = function() {
return ($scope.is5min()) ? '>>' : '<<';
};
$scope.toggleManual5min = function() {
$scope.manual5min = !$scope.is5min();
};
$scope.is5min=function(){
if($scope.manual5min === true || $scope.manual5min === false) {
return $scope.manual5min;
}
else {
return $scope.show5min;
}
};
if (!$attrs.tabindex) {
$element.attr('tabindex', '-1');
}
var self = this;
this.hourClickHandler = function(displayVal) {
var updated = new Date(self.displayTime).setHours(Number(displayVal));
self.setNgModelValue(updated, 'hours');
};
$scope.hourClickHandler = this.hourClickHandler;
this.minuteClickHandler = function(displayVal) {
//remove leading ':'
var val = displayVal.substr(1);
var updated = new Date(self.displayTime).setMinutes(Number(val));
self.setNgModelValue(updated, 'minutes');
};
$scope.minuteClickHandler = this.minuteClickHandler;
this.attachTimePaneEventListeners();
}
TimePaneCtrl.$inject = ["$element", "$attrs", "$scope", "$animate", "$q", "$mdConstant", "$mdTheming", "$$mdDateUtil", "$mdDateLocale", "$mdInkRipple", "$mdUtil"];
TimePaneCtrl.prototype.configureNgModel = function(ngModelCtrl, sgTimePaneCtrl, timePaneElement) {
this.ngModelCtrl = ngModelCtrl;
var self = this;
ngModelCtrl.$render = function() {
self.changeSelectedTime(self.ngModelCtrl.$viewValue, sgTimePaneCtrl, timePaneElement);
};
};
/**
* Change the selected date in the time (ngModel value has already been changed).
*/
TimePaneCtrl.prototype.changeSelectedTime = function(date, sgTimePaneCtrl, timePaneElement) {
var self = this;
var previousSelectedTime = this.selectedTime;
this.selectedTime = new Date(date);
this.changeDisplayTime(date).then(function() {
// Remove the selected class from the previously selected date, if any.
if (previousSelectedTime) {
var prevH = previousSelectedTime.getHours();
var prevHCell = document.getElementById('tp-'+sgTimePaneCtrl.id+'-hour-'+prevH);
if (prevHCell) {
prevHCell.classList.remove(SELECTED_TIME_CLASS2);
prevHCell.setAttribute('aria-selected', 'false');
}
var prevM = previousSelectedTime.getMinutes();
var prevMCell = document.getElementById('tp-'+sgTimePaneCtrl.id+'-minute-'+prevM);
if (prevMCell) {
prevMCell.classList.remove(SELECTED_TIME_CLASS2);
prevMCell.setAttribute('aria-selected', 'false');
}
var prevM5Cell = document.getElementById('tp-'+sgTimePaneCtrl.id+'-minute5-'+prevM);
if (prevM5Cell) {
prevM5Cell.classList.remove(SELECTED_TIME_CLASS2);
prevM5Cell.setAttribute('aria-selected', 'false');
}
}
// Apply the select class to the new selected date if it is set.
if (date) {
var d = new Date(date);
var newH = d.getHours();
var mCell, hCell = document.getElementById('tp-'+sgTimePaneCtrl.id+'-hour-'+newH);
if (hCell) {
hCell.classList.add(SELECTED_TIME_CLASS2);
hCell.setAttribute('aria-selected', 'true');
}
var newM = d.getMinutes();
if (newM % 5 === 0) {
sgTimePaneCtrl.$scope.show5min = true;
mCell = document.getElementById('tp-'+sgTimePaneCtrl.id+'-minute5-'+newM);
if (mCell) {
mCell.classList.add(SELECTED_TIME_CLASS2);
mCell.setAttribute('aria-selected', 'true');
}
}
else {
sgTimePaneCtrl.$scope.show5min = false;
}
mCell = document.getElementById('tp-'+sgTimePaneCtrl.id+'-minute-'+newM);
if (mCell) {
mCell.classList.add(SELECTED_TIME_CLASS2);
mCell.setAttribute('aria-selected', 'true');
}
}
});
};
TimePaneCtrl.prototype.changeDisplayTime = function(date) {
var d = new Date(date);
if (!this.isInitialized) {
this.buildInitialTimePaneDisplay();
return this.$q.when();
}
if (!this.dateUtil.isValidDate(d)) {
return this.$q.when();
}
this.displayTime = d;
return this.$q.when();
};
TimePaneCtrl.prototype.buildInitialTimePaneDisplay = function() {
this.displayTime = this.selectedTime || this.today;
this.isInitialized = true;
};
TimePaneCtrl.prototype.attachTimePaneEventListeners = function() {
// Keyboard interaction.
this.$element.on('keydown', angular.bind(this, this.handleKeyEvent));
};
/*** User input handling ***/
/**
* Handles a key event in the calendar with the appropriate action. The action will either
* be to select the focused date or to navigate to focus a new date.
* @param {KeyboardEvent} event
*/
TimePaneCtrl.prototype.handleKeyEvent = function(event) {
var self = this;
this.$scope.$apply(function() {
// Capture escape and emit back up so that a wrapping component
// (such as a time-picker) can decide to close.
if (event.which == self.keyCode.ESCAPE || event.which == self.keyCode.TAB) {
self.$scope.$emit('md-time-pane-close');
if (event.which == self.keyCode.TAB) {
event.preventDefault();
}
return;
}
// Remaining key events fall into two categories: selection and navigation.
// Start by checking if this is a selection event.
if (event.which === self.keyCode.ENTER) {
self.setNgModelValue(self.displayTime, 'enter');
event.preventDefault();
return;
}
// Selection isn't occuring, so the key event is either navigation or nothing.
/*var date = self.getFocusDateFromKeyEvent(event);
if (date) {
event.preventDefault();
event.stopPropagation();
// Since this is a keyboard interaction, actually give the newly focused date keyboard
// focus after the been brought into view.
self.changeDisplayTime(date).then(function () {
self.focus(date);
});
}*/
});
};
/**
* Sets the ng-model value for the time pane and emits a change event.
* @param {Date} date
*/
TimePaneCtrl.prototype.setNgModelValue = function(date, mode) {
this.$scope.$emit('sg-time-pane-change', {date:date, changed:mode});
this.ngModelCtrl.$setViewValue(date);
this.ngModelCtrl.$render();
};
/**
* Focus the cell corresponding to the given date.
* @param {Date=} opt_date
*/
TimePaneCtrl.prototype.focus = function(opt_date, sgTimePaneCtrl) {
var date = opt_date || this.selectedTime || this.today;
var previousFocus = this.timePaneElement.querySelector('.md-focus');
if (previousFocus) {
previousFocus.classList.remove(FOCUSED_TIME_CLASS);
}
if (date) {
var newH = date.getHours();
var hCell = document.getElementById('tp-'+sgTimePaneCtrl.id+'-hour-'+newH);
if (hCell) {
hCell.classList.add(FOCUSED_TIME_CLASS);
hCell.focus();
}
}
};
})();
(function() {
'use strict';
angular.module('SOGo.Common')
.directive('sgTimepicker', timePickerDirective);
/**
* @ngdoc directive
* @name mdTimepicker
* @module material.components.timepicker
*
* @param {Date} ng-model The component's model. Expects a JavaScript Date object.
* @param {expression=} ng-change Expression evaluated when the model value changes.
* @param {boolean=} disabled Whether the timepicker is disabled.
*
* @description
* `<sg-timepicker>` is a component used to select a single time.
* For information on how to configure internationalization for the time picker,
* see `$mdTimeLocaleProvider`.
*
* @usage
* <hljs lang="html">
* <sg-timepicker ng-model="birthday"></sg-timepicker>
* </hljs>
*
*/
function timePickerDirective() {
return {
template:
// Buttons are not in the tab order because users can open the hours pane via keyboard
// interaction on the text input, and multiple tab stops for one component (picker)
// may be confusing.
'<md-button class="sg-timepicker-button md-icon-button" type="button" ' +
'tabindex="-1" aria-hidden="true" ' +
'ng-click="ctrl.openTimePane($event)">' +
//'<md-icon class="md-timepicker-calendar-icon" md-svg-icon="md-calendar"></md-icon>' +
'<i class="material-icons">access_time</i>' +
'</md-button>' +
'<div class="sg-timepicker-input-container" ' +
'ng-class="{\'sg-timepicker-focused\': ctrl.isFocused}">' +
'<input class="sg-timepicker-input" aria-haspopup="true" ' +
'ng-focus="ctrl.setFocused(true)" ng-blur="ctrl.setFocused(false)">' +
'<md-button type="button" md-no-ink ' +
'class="sg-timepicker-triangle-button md-icon-button" ' +
'ng-click="ctrl.openTimePane($event)" ' +
'aria-label="{{::ctrl.dateLocale.msgOpenCalendar}}">' +
'<div class="sg-timepicker-expand-triangle"></div>' +
'</md-button>' +
'</div>' +
// This pane will be detached from here and re-attached to the document body.
'<div class="sg-timepicker-time-pane md-whiteframe-z1">' +
'<div class="sg-timepicker-input-mask">' +
'<div class="sg-timepicker-input-mask-opaque"></div>' +
'</div>' +
'<div class="sg-timepicker-time">' +
'<sg-time-pane role="dialog" aria-label="{{::ctrl.dateLocale.msgCalendar}}" ' +
'ng-model="ctrl.time" ng-if="ctrl.isTimeOpen"></sg-time-pane>' +
'</div>' +
'</div>',
require: ['ngModel', 'sgTimepicker'],
scope: {
placeholder: '@mdPlaceholder'
},
controller: TimePickerCtrl,
controllerAs: 'ctrl',
bindToController: true,
link: function(scope, element, attr, controllers) {
var ngModelCtrl = controllers[0];
var mdTimePickerCtrl = controllers[1];
mdTimePickerCtrl.configureNgModel(ngModelCtrl);
}
};
}
/** Additional offset for the input's `size` attribute, which is updated based on its content. */
var EXTRA_INPUT_SIZE = 3;
/** Class applied to the container if the date is invalid. */
var INVALID_CLASS = 'sg-timepicker-invalid';
/** Default time in ms to debounce input event by. */
var DEFAULT_DEBOUNCE_INTERVAL = 500;
/**
* Controller for sg-timepicker.
*
* ngInject @constructor
*/
function TimePickerCtrl($scope, $element, $attrs, $compile, $timeout, $mdConstant, $mdTheming,
$mdUtil, $mdDateLocale, $$mdDateUtil, $$rAF) {
/** @final */
this.$compile = $compile;
/** @final */
this.$timeout = $timeout;
/** @final */
this.dateLocale = $mdDateLocale;
/** @final */
this.dateUtil = $$mdDateUtil;
/** @final */
this.$mdConstant = $mdConstant;
/* @final */
this.$mdUtil = $mdUtil;
/** @final */
this.$$rAF = $$rAF;
/** @type {!angular.NgModelController} */
this.ngModelCtrl = null;
/** @type {HTMLInputElement} */
this.inputElement = $element[0].querySelector('input');
/** @type {HTMLElement} */
this.inputContainer = $element[0].querySelector('.sg-timepicker-input-container');
/** @type {HTMLElement} Floating time pane. */
this.timePane = $element[0].querySelector('.sg-timepicker-time-pane');
/** @type {HTMLElement} Time icon button. */
this.timeButton = $element[0].querySelector('.sg-timepicker-button');
/**
* Element covering everything but the input in the top of the floating calendar pane.
* @type {HTMLElement}
*/
this.inputMask = $element[0].querySelector('.sg-timepicker-input-mask-opaque');
/** @final {!angular.JQLite} */
this.$element = $element;
/** @final {!angular.Attributes} */
this.$attrs = $attrs;
/** @final {!angular.Scope} */
this.$scope = $scope;
/** @type {Date} */
this.date = null;
/** @type {boolean} */
this.isFocused = false;
/** @type {boolean} */
this.isDisabled = false;
this.setDisabled($element[0].disabled || angular.isString($attrs.disabled));
/** @type {boolean} Whether the date-picker's calendar pane is open. */
this.isTimeOpen = false;
/**
* Element from which the calendar pane was opened. Keep track of this so that we can return
* focus to it when the pane is closed.
* @type {HTMLElement}
*/
this.timePaneOpenedFrom = null;
this.timePane.id = 'sg-time-pane' + $mdUtil.nextUid();
$mdTheming($element);
/** Pre-bound click handler is saved so that the event listener can be removed. */
this.bodyClickHandler = angular.bind(this, this.handleBodyClick);
// Unless the user specifies so, the datepicker should not be a tab stop.
// This is necessary because ngAria might add a tabindex to anything with an ng-model
// (based on whether or not the user has turned that particular feature on/off).
if (!$attrs.tabindex) {
$element.attr('tabindex', '-1');
}
this.installPropertyInterceptors();
this.attachChangeListeners();
this.attachInteractionListeners();
var self = this;
$scope.$on('$destroy', function() {
self.detachTimePane();
});
}
TimePickerCtrl.$inject = ["$scope", "$element", "$attrs", "$compile", "$timeout", "$mdConstant", "$mdTheming",
"$mdUtil", "$mdDateLocale", "$$mdDateUtil", "$$rAF"];
/**
* Sets up the controller's reference to ngModelController.
* @param {!angular.NgModelController} ngModelCtrl
*/
TimePickerCtrl.prototype.configureNgModel = function(ngModelCtrl) {
this.ngModelCtrl = ngModelCtrl;
var self = this;
ngModelCtrl.$render = function() {
self.time = self.ngModelCtrl.$viewValue;
self.inputElement.value = self.formatTime(self.time);
self.resizeInputElement();
};
};
TimePickerCtrl.prototype.formatTime = function(time) {
var t = new Date(time);
if(t) {
var h= t.getHours();
var m= t.getMinutes();
return (h<10?('0'+ h) : h) + ':' + (m<10?'0'+ m : m);
}
else return '';
};
/**
* Attach event listeners for both the text input and the md-time.
* Events are used instead of ng-model so that updates don't infinitely update the other
* on a change. This should also be more performant than using a $watch.
*/
TimePickerCtrl.prototype.attachChangeListeners = function() {
var self = this;
self.$scope.$on('sg-time-pane-change', function(event, data) {
var time = new Date(data.date);
self.ngModelCtrl.$setViewValue(time);
self.time = time;
self.inputElement.value = self.formatTime(self.time);
if(data.changed == 'minutes') {
self.closeTimePane();
}
self.resizeInputElement();
self.inputContainer.classList.remove(INVALID_CLASS);
});
var ngElement = angular.element(self.inputElement);
ngElement.on('input', angular.bind(self, self.resizeInputElement));
ngElement.on('input', self.$mdUtil.debounce(self.handleInputEvent,
DEFAULT_DEBOUNCE_INTERVAL, self));
};
/** Attach event listeners for user interaction. */
TimePickerCtrl.prototype.attachInteractionListeners = function() {
var self = this;
var $scope = this.$scope;
var keyCodes = this.$mdConstant.KEY_CODE;
// Add event listener through angular so that we can triggerHandler in unit tests.
angular.element(self.inputElement).on('keydown', function(event) {
if (event.altKey && event.keyCode == keyCodes.DOWN_ARROW) {
self.openTimePane(event);
$scope.$digest();
}
});
$scope.$on('md-time-close', function() {
self.closeTimePane();
});
};
/**
* Capture properties set to the time-picker and imperitively handle internal changes.
* This is done to avoid setting up additional $watches.
*/
TimePickerCtrl.prototype.installPropertyInterceptors = function() {
var self = this;
if (this.$attrs.ngDisabled) {
// The expression is to be evaluated against the directive element's scope and not
// the directive's isolate scope.
this.$element.scope().$watch(this.$attrs.ngDisabled, function(isDisabled) {
self.setDisabled(isDisabled);
});
}
Object.defineProperty(this, 'placeholder', {
get: function() { return self.inputElement.placeholder; },
set: function(value) { self.inputElement.placeholder = value || ''; }
});
};
/**
* Sets whether the date-picker is disabled.
* @param {boolean} isDisabled
*/
TimePickerCtrl.prototype.setDisabled = function(isDisabled) {
this.isDisabled = isDisabled;
this.inputElement.disabled = isDisabled;
this.timeButton.disabled = isDisabled;
};
/**
* Resizes the input element based on the size of its content.
*/
TimePickerCtrl.prototype.resizeInputElement = function() {
this.inputElement.size = this.inputElement.value.length + EXTRA_INPUT_SIZE;
};
/**
* Sets the model value if the user input is a valid time.
* Adds an invalid class to the input element if not.
*/
TimePickerCtrl.prototype.handleInputEvent = function(self) {
var inputString = this.inputElement.value;
var arr = inputString.split(':');
if(arr.length < 2) {return;}
var h=Number(arr[0]);
var m=Number(arr[1]);
var newVal = new Date(this.time);
if (h && h>=0 && h<=23 && m && m>=0 && m<= 59 && angular.isDate(newVal)) {
newVal.setHours(h);
newVal.setMinutes(m);
this.ngModelCtrl.$setViewValue(newVal);
this.time = newVal;
this.inputContainer.classList.remove(INVALID_CLASS);
}
else {
// If there's an input string, it's an invalid time.
this.inputContainer.classList.toggle(INVALID_CLASS, inputString);
}
};
/** Position and attach the floating calendar to the document. */
TimePickerCtrl.prototype.attachTimePane = function() {
var timePane = this.timePane;
this.$element.addClass('sg-timepicker-open');
var elementRect = this.inputContainer.getBoundingClientRect();
var bodyRect = document.body.getBoundingClientRect();
timePane.style.left = (elementRect.left - bodyRect.left) + 'px';
timePane.style.top = (elementRect.top - bodyRect.top) + 'px';
document.body.appendChild(this.timePane);
// The top of the calendar pane is a transparent box that shows the text input underneath.
// Since the pane is flowing, though, the page underneath the pane *adjacent* to the input is
// also shown unless we cover it up. The inputMask does this by filling up the remaining space
// based on the width of the input.
this.inputMask.style.left = elementRect.width + 'px';
// Add CSS class after one frame to trigger open animation.
this.$$rAF(function() {
timePane.classList.add('md-pane-open');
});
};
/** Detach the floating time pane from the document. */
TimePickerCtrl.prototype.detachTimePane = function() {
this.$element.removeClass('sg-timepicker-open');
this.timePane.classList.remove('md-pane-open');
if (this.timePane.parentNode) {
// Use native DOM removal because we do not want any of the angular state of this element
// to be disposed.
this.timePane.parentNode.removeChild(this.timePane);
}
};
/**
* Open the floating time pane.
* @param {Event} event
*/
TimePickerCtrl.prototype.openTimePane = function(event) {
if (!this.isTimeOpen && !this.isDisabled) {
this.isTimeOpen = true;
this.timePaneOpenedFrom = event.target;
this.attachTimePane();
this.focusTime();
// Because the time pane is attached directly to the body, it is possible that the
// rest of the component (input, etc) is in a different scrolling container, such as
// an md-content. This means that, if the container is scrolled, the pane would remain
// stationary. To remedy this, we disable scrolling while the time pane is open, which
// also matches the native behavior for things like `<select>` on Mac and Windows.
this.$mdUtil.disableScrollAround(this.timePane);
// Attach click listener inside of a timeout because, if this open call was triggered by a
// click, we don't want it to be immediately propogated up to the body and handled.
var self = this;
this.$mdUtil.nextTick(function() {
document.body.addEventListener('click', self.bodyClickHandler);
}, false);
}
};
/** Close the floating time pane. */
TimePickerCtrl.prototype.closeTimePane = function() {
this.isTimeOpen = false;
this.detachTimePane();
this.timePaneOpenedFrom.focus();
this.timePaneOpenedFrom = null;
this.$mdUtil.enableScrolling();
document.body.removeEventListener('click', this.bodyClickHandler);
};
/** Gets the controller instance for the time in the floating pane. */
TimePickerCtrl.prototype.getTimePaneCtrl = function() {
return angular.element(this.timePane.querySelector('sg-time-pane')).controller('sgTimePane');
};
/** Focus the time in the floating pane. */
TimePickerCtrl.prototype.focusTime = function() {
// Use a timeout in order to allow the time to be rendered, as it is gated behind an ng-if.
var self = this;
this.$mdUtil.nextTick(function() {
var ctrl = self.getTimePaneCtrl();
self.getTimePaneCtrl().focus(null, ctrl);
}, false);
};
/**
* Sets whether the input is currently focused.
* @param {boolean} isFocused
*/
TimePickerCtrl.prototype.setFocused = function(isFocused) {
this.isFocused = isFocused;
};
/**
* Handles a click on the document body when the floating time pane is open.
* Closes the floating time pane if the click is not inside of it.
* @param {MouseEvent} event
*/
TimePickerCtrl.prototype.handleBodyClick = function(event) {
if (this.isTimeOpen) {
// TODO(jelbourn): way want to also include the md-datepicker itself in this check.
var isInTime = this.$mdUtil.getClosest(event.target, 'sg-time-pane');
if (!isInTime) {
this.closeTimePane();
}
this.$scope.$digest();
}
};
})();
+7 -5
View File
@@ -80,7 +80,7 @@ String.prototype.md5 = function() {
String.prototype.capitalize = function() {
return this.charAt(0).toUpperCase() + this.slice(1);
};
}
String.prototype.asDate = function () {
var newDate;
@@ -129,7 +129,7 @@ String.prototype.formatTime = function(hours, minutes) {
};
Date.prototype.daysUpTo = function(otherDate) {
var days = [];
var days = new Array();
var day1 = this.getTime();
var day2 = otherDate.getTime();
@@ -155,8 +155,10 @@ String.prototype.isValidEmail = function() {
};
String.prototype.asCSSIdentifier = function() {
var characters = [ '_' , '\\.', '#' , '@' , '\\*', ':' , ',' , ' ', "'", '&', '\\+' ];
var escapeds = [ '_U_', '_D_', '_H_', '_A_', '_S_', '_C_', '_CO_', '_SP_', '_SQ_', '_AM_', '_P_' ];
var characters = [ '_' , '\\.', '#' , '@' , '\\*', ':' , ',' , ' '
, "'", '&', '\\+' ];
var escapeds = [ '_U_', '_D_', '_H_', '_A_', '_S_', '_C_', '_CO_',
'_SP_', '_SQ_', '_AM_', '_P_' ];
var newString = this;
for (var i = 0; i < characters.length; i++) {
@@ -229,7 +231,7 @@ Date.prototype.beginOfDay = function() {
beginOfDay.setMilliseconds(0);
return beginOfDay;
};
}
Date.prototype.beginOfWeek = function() {
var offset = firstDayOfWeek - this.getDay();
@@ -4,7 +4,7 @@
(function() {
'use strict';
angular.module('SOGo.ContactsUI', ['ngSanitize', 'ui.router', 'angularFileUpload', 'ck', 'SOGo.Common', 'SOGo.PreferencesUI', 'SOGo.MailerUI'])
angular.module('SOGo.ContactsUI', ['ngSanitize', 'ui.router', 'SOGo.Common', 'SOGo.PreferencesUI'])
.config(configure)
.run(runBlock);
-2
View File
@@ -1,2 +0,0 @@
!function(){"use strict";function configure($stateProvider,$urlRouterProvider){$stateProvider.state("app",{url:"/addressbooks","abstract":!0,views:{addressbooks:{templateUrl:"UIxContactFoldersView",controller:"AddressBooksController",controllerAs:"app"}},resolve:{stateAddressbooks:stateAddressbooks}}).state("app.addressbook",{url:"/:addressbookId",views:{addressbook:{templateUrl:"addressbook",controller:"AddressBookController",controllerAs:"addressbook"}},resolve:{stateAddressbook:stateAddressbook}}).state("app.addressbook.new",{url:"/{contactType:(?:card|list)}/new",views:{card:{templateUrl:"UIxContactEditorTemplate",controller:"CardController",controllerAs:"editor"}},resolve:{stateCard:stateNewCard}}).state("app.addressbook.card",{url:"/:cardId","abstract":!0,views:{card:{template:"<ui-view/>"}},resolve:{stateCard:stateCard}}).state("app.addressbook.card.view",{url:"/view",views:{"card@app.addressbook":{templateUrl:"UIxContactViewTemplate",controller:"CardController",controllerAs:"editor"}}}).state("app.addressbook.card.editor",{url:"/edit",views:{"card@app.addressbook":{templateUrl:"UIxContactEditorTemplate",controller:"CardController",controllerAs:"editor"}}}),$urlRouterProvider.otherwise("/addressbooks/personal")}function stateAddressbooks(AddressBook){return AddressBook.$findAll(window.contactFolders)}function stateAddressbook($stateParams,AddressBook){return AddressBook.$find($stateParams.addressbookId).$futureAddressBookData}function stateNewCard($stateParams,stateAddressbook,Card){var tag="v"+$stateParams.contactType,card=new Card({pid:$stateParams.addressbookId,c_component:tag});return stateAddressbook.selectedCard=!0,card}function stateCard($stateParams,stateAddressbook){return stateAddressbook.selectedCard=$stateParams.cardId,stateAddressbook.$getCard($stateParams.cardId)}function runBlock($rootScope){$rootScope.$on("$routeChangeError",function(event,current,previous,rejection){console.error(event,current,previous,rejection)})}angular.module("SOGo.ContactsUI",["ngSanitize","ui.router","angularFileUpload","ck","SOGo.Common","SOGo.PreferencesUI","SOGo.MailerUI"]).config(configure).run(runBlock),configure.$inject=["$stateProvider","$urlRouterProvider"],stateAddressbooks.$inject=["AddressBook"],stateAddressbook.$inject=["$stateParams","AddressBook"],stateNewCard.$inject=["$stateParams","stateAddressbook","Card"],stateCard.$inject=["$stateParams","stateAddressbook"],runBlock.$inject=["$rootScope"]}(),function(){"use strict";function AddressBookController($scope,$q,$state,$timeout,$mdDialog,focus,Account,Card,AddressBook,Dialog,Settings,stateAddressbooks,stateAddressbook){function selectCard(card){$state.go("app.addressbook.card.view",{addressbookId:stateAddressbook.id,cardId:card.id})}function newComponent(ev){function ComponentDialogController(scope,$mdDialog,$state,addressbookId){scope.create=function(type){$mdDialog.hide(),$state.go("app.addressbook.new",{addressbookId:addressbookId,contactType:type})}}$mdDialog.show({parent:angular.element(document.body),targetEvent:ev,clickOutsideToClose:!0,escapeToClose:!0,template:['<md-dialog aria-label="'+l("Create component")+'">'," <md-dialog-content>",' <div layout="column">'," <md-button ng-click=\"create('card')\">"," "+l("Contact")," </md-button>"," <md-button ng-click=\"create('list')\">"," "+l("List")," </md-button>"," </div>"," </md-dialog-content>","</md-dialog>"].join(""),locals:{addressbookId:vm.selectedFolder.id},controller:ComponentDialogController}),ComponentDialogController.$inject=["scope","$mdDialog","$state","addressbookId"]}function notSelectedComponent(currentCard,type){return currentCard&&currentCard.c_component==type&&!currentCard.selected}function unselectCards(){_.each(vm.selectedFolder.cards,function(card){card.selected=!1})}function confirmDeleteSelectedCards(){Dialog.confirm(l("Warning"),l("Are you sure you want to delete the selected contacts?")).then(function(){var selectedCards=_.filter(vm.selectedFolder.cards,function(card){return card.selected});vm.selectedFolder.$deleteCards(selectedCards),delete vm.selectedFolder.selectedCard},function(data,status){})}function saveSelectedCards(){var selectedCards=_.filter(vm.selectedFolder.cards,function(card){return card.selected}),selectedUIDs=_.pluck(selectedCards,"id");window.location.href=ApplicationBaseURL+"/"+vm.selectedFolder.id+"/export?uid="+selectedUIDs.join("&uid=")}function copySelectedCards(folder){var selectedCards=_.filter(vm.selectedFolder.cards,function(card){return card.selected});vm.selectedFolder.$copyCards(selectedCards,folder).then(function(){},function(error){Dialog.alert(l("Error"),error)})}function selectAll(){_.each(vm.selectedFolder.cards,function(card){card.selected=!0})}function sort(field){vm.selectedFolder.$filter("",{sort:field})}function sortedBy(field){return AddressBook.$query.sort==field}function cancelSearch(){vm.mode.search=!1,vm.selectedFolder.$filter("")}function newMessage($event,recipients){Account.$findALine truncated
//# sourceMappingURL=Contacts.js.map
-1
View File
@@ -1 +0,0 @@
{"version":3,"file":"Contacts.js","sources":["Contacts/Contacts.app.js","Contacts/AddressBookController.js","Contacts/AddressBooksController.js","Contacts/CardController.js","Contacts/sgAddress.directive.js"],"names":["configure","$stateProvider","$urlRouterProvider","state","url","abstract","views","addressbooks","templateUrl","controller","controllerAs","resolve","stateAddressbooks","addressbook","stateAddressbook","card","stateCard","stateNewCard","template","card@app.addressbook","otherwise","AddressBook","$findAll","window","contactFolders","$stateParams","$find","addressbookId","$futureAddressBookData","Card","tag","contactType","pid","c_component","selectedCard","cardId","$getCard","runBlock","$rootScope","$on","event","current","previous","rejection","console","error","angular","module","config","run","$inject","AddressBookController","$scope","$q","$state","$timeout","$mdDialog","focus","Account","Dialog","Settings","selectCard","go","id","newComponent","ev","ComponentDialogController","scope","create","type","hide","show","parent","element","document","body","targetEvent","clickOutsideToClose","escapeToClose","l","join","locals","vm","selectedFolder","notSelectedComponent","currentCard","selected","unselectCards","_","each","cards","confirmDeleteSelectedCards","confirm","then","selectedCards","filter","$deleteCards","data","status","saveSelectedCards","selectedUIDs","pluck","location","href","ApplicationBaseURL","copySelectedCards","folder","$copyCards","alert","selectAll","sort","field","$filter","sortedBy","$query","cancelSearch","mode","search","newMessage","$event","recipients","accounts","account","o","$getMailboxes","mailboxes","$newMessage","message","stateAccounts","stateMessage","stateRecipients","newMessageWithRecipient","recipient","fn","full","newMessageWithSelectedCards","promises","c_mail","length","push","c_cn","isDefined","refs","ref","email","$futureCardData","all","this","AddressBooksController","$mdToast","FileUploader","User","select","editMode","value","newAddressbook","prompt","name","isEditable","isRemote","owner","UserLogin","$add","edit","originalAddressbook","extend","$omit","revertEditing","save","$rename","confirmDelete","service","isSubscription","$delete","importCards","CardsImportDialogController","uploader","onProgressItem","item","progress","debug","onSuccessItem","response","headers","JSON","stringify","undefined","simple","content","imported","position","hideDelay","$reload","onCancelItem","onErrorItem","close","upload","uploadAll","exportCards","showLinks","LinksDialogController","share","$acl","$users","usersWithACL","users","subscribeToFolder","addressbookData","$subscribe","activeUser","CardController","addOrgUnit","i","$addOrgUnit","addBirthday","birthday","Date","addEmail","$addEmail","addPhone","$addPhone","addUrl","$addUrl","addAddress","$addAddress","addMember","$addMember","userFilter","excludedCards","dry","excludeLists","$cards","form","$valid","$save","indexOf","copy","err","log","reset","$reset","cancel","isNew","$fullname","ok","reject","exportCard","currentFolder","viewRawSource","$$resource","post","CardRawSourceDialogController","allEmailTypes","$EMAIL_TYPES","allTelTypes","$TEL_TYPES","allUrlTypes","$URL_TYPES","allAddressTypes","$ADDRESS_TYPES","categories","userFilterResults","sgAddress","restrict","addressLines","lines","locality_region","street","street2","locality","region","country","postalcode","directive"],"mappings":"CAGA,WACE,YAUA,SAASA,WAAUC,eAAgBC,oBACjCD,eACGE,MAAM,OACLC,IAAK,gBACLC,YAAU,EACVC,OACEC,cACEC,YAAa,wBACbC,WAAY,yBACZC,aAAc,QAGlBC,SACEC,kBAAmBA,qBAGtBT,MAAM,mBACLC,IAAK,kBACLE,OACEO,aACEL,YAAa,cACbC,WAAY,wBACZC,aAAc,gBAGlBC,SACEG,iBAAkBA,oBAGrBX,MAAM,uBACLC,IAAK,mCACLE,OACES,MACEP,YAAa,2BACbC,WAAY,iBACZC,aAAc,WAGlBC,SACEK,UAAWC,gBAGdd,MAAM,wBACLC,IAAK,WACLC,YAAU,EACVC,OACES,MACEG,SAAU,eAGdP,SACEK,UAAWA,aAGdb,MAAM,6BACLC,IAAK,QACLE,OACEa,wBACEX,YAAa,yBACbC,WAAY,iBACZC,aAAc,aAInBP,MAAM,+BACLC,IAAK,QACLE,OACEa,wBACEX,YAAa,2BACbC,WAAY,iBACZC,aAAc,aAMtBR,mBAAmBkB,UAAU,0BAO/B,QAASR,mBAAkBS,aACzB,MAAOA,aAAYC,SAASC,OAAOC,gBAOrC,QAASV,kBAAiBW,aAAcJ,aACtC,MAAOA,aAAYK,MAAMD,aAAaE,eAAeC,uBAOvD,QAASX,cAAaQ,aAAcX,iBAAkBe,MACpD,GAAIC,KAAM,IAAML,aAAaM,YACzBhB,KAAO,GAAIc,OAAOG,IAAKP,aAAaE,cAAeM,YAAaH,KAEpE,OADAhB,kBAAiBoB,cAAe,EACzBnB,KAOT,QAASC,WAAUS,aAAcX,kBAE/B,MADAA,kBAAiBoB,aAAeT,aAAaU,OACtCrB,iBAAiBsB,SAASX,aAAaU,QAOhD,QAASE,UAASC,YAChBA,WAAWC,IAAI,oBAAqB,SAASC,MAAOC,QAASC,SAAUC,WACrEC,QAAQC,MAAML,MAAOC,QAASC,SAAUC,aAjI5CG,QAAQC,OAAO,mBAAoB,aAAc,YAAa,oBAAqB,KAAM,cAAe,qBAAsB,kBAC3HC,OAAOhD,WACPiD,IAAIZ,UAKPrC,UAAUkD,SAAW,iBAAkB,sBAmFvCtC,kBAAkBsC,SAAW,eAQ7BpC,iBAAiBoC,SAAW,eAAgB,eAQ5CjC,aAAaiC,SAAW,eAAgB,mBAAoB,QAW5DlC,UAAUkC,SAAW,eAAgB,oBASrCb,SAASa,SAAW,iBClItB,WACE,YAMA,SAASC,uBAAsBC,OAAQC,GAAIC,OAAQC,SAAUC,UAAWC,MAAOC,QAAS7B,KAAMR,YAAasC,OAAQC,SAAUhD,kBAAmBE,kBAsB9I,QAAS+C,YAAW9C,MAClBuC,OAAOQ,GAAG,6BAA8BnC,cAAeb,iBAAiBiD,GAAI5B,OAAQpB,KAAKgD,KAG3F,QAASC,cAAaC,IA8BpB,QAASC,2BAA0BC,MAAOX,UAAWF,OAAQ3B,eAC3DwC,MAAMC,OAAS,SAASC,MACtBLine truncated
@@ -1,2 +0,0 @@
!function(){"use strict";function AddressBook(futureAddressBookData){if("function"!=typeof futureAddressBookData.then)if(this.init(futureAddressBookData),this.name&&!this.id){var newAddressBookData=AddressBook.$$resource.create("createFolder",this.name);this.$unwrap(newAddressBookData)}else this.id&&(this.$acl=new AddressBook.$$Acl("Contacts/"+this.id));else this.$unwrap(futureAddressBookData)}AddressBook.$factory=["$q","$timeout","$log","sgSettings","Resource","Card","Acl","Preferences",function($q,$timeout,$log,Settings,Resource,Card,Acl,Preferences){return angular.extend(AddressBook,{$q:$q,$timeout:$timeout,$log:$log,$$resource:new Resource(Settings.activeUser("folderURL")+"Contacts",Settings.activeUser()),$Card:Card,$$Acl:Acl,$Preferences:Preferences,$query:{search:"name_or_address",value:"",sort:"c_cn",asc:1},activeUser:Settings.activeUser(),selectedFolder:null,$refreshTimeout:null}),Preferences.ready().then(function(){Preferences.settings.Contact.SortingState&&(AddressBook.$query.sort=Preferences.settings.Contact.SortingState[0],AddressBook.$query.asc=parseInt(Preferences.settings.Contact.SortingState[1]))}),AddressBook}];try{angular.module("SOGo.ContactsUI")}catch(e){angular.module("SOGo.ContactsUI",["SOGo.Common"])}angular.module("SOGo.ContactsUI").factory("AddressBook",AddressBook.$factory),AddressBook.$filterAll=function(search,options,excludedCards){var params={search:search};if(!search)return AddressBook.$cards=[],AddressBook.$q.when(AddressBook.$cards);if(angular.isUndefined(AddressBook.$cards))AddressBook.$cards=[];else if(AddressBook.$query==search)return AddressBook.$q.when(AddressBook.$cards);return AddressBook.$query=search,angular.extend(params,options),AddressBook.$$resource.fetch(null,"allContactSearch",params).then(function(response){var results,card,index,compareIds=function(data){return this.id==data.id};for(results=excludedCards?_.filter(response.contacts,function(data){return _.isUndefined(_.find(excludedCards,compareIds,data))}):response.contacts,index=AddressBook.$cards.length-1;index>=0;index--)card=AddressBook.$cards[index],_.isUndefined(_.find(results,compareIds,card))&&AddressBook.$cards.splice(index,1);return _.each(results,function(data,index){if(_.isUndefined(_.find(AddressBook.$cards,compareIds,data))){var card=new AddressBook.$Card(data,search);AddressBook.$cards.splice(index,0,card)}}),AddressBook.$cards})},AddressBook.$add=function(addressbook){var list,sibling,i;list=addressbook.isSubscription?this.$subscriptions:this.$addressbooks,sibling=_.find(list,function(o){return"personal"==addressbook.id||"personal"!=o.id&&1===o.name.localeCompare(addressbook.name)}),i=sibling?_.indexOf(_.pluck(list,"id"),sibling.id):1,list.splice(i,0,addressbook)},AddressBook.$findAll=function(data){var _this=this;return data&&(this.$addressbooks=[],this.$subscriptions=[],this.$remotes=[],angular.forEach(data,function(o,i){var addressbook=new AddressBook(o);addressbook.isRemote?_this.$remotes.push(addressbook):addressbook.isSubscription?_this.$subscriptions.push(addressbook):_this.$addressbooks.push(addressbook)})),_.union(this.$addressbooks,this.$subscriptions,this.$remotes)},AddressBook.$find=function(addressbookId){var futureAddressBookData=AddressBook.$Preferences.ready().then(function(){return AddressBook.$$resource.fetch(addressbookId,"view",AddressBook.$query)});return new AddressBook(futureAddressBookData)},AddressBook.$subscribe=function(uid,path){var _this=this;return AddressBook.$$resource.userResource(uid).fetch(path,"subscribe").then(function(addressbookData){var addressbook=new AddressBook(addressbookData);return _.isUndefined(_.find(_this.$subscriptions,function(o){return o.id==addressbookData.id}))&&AddressBook.$add(addressbook),addressbook})},AddressBook.prototype.init=function(data){this.$isLoading=!0,this.$cards=[],this.cards=[],angular.extend(this,data),this.isOwned=AddressBook.activeUser.isSuperUser||this.owner==AddressBook.activeUser.login,this.isSubscription=!this.isRemote&&this.owner!=AddressBook.activeUser.login},AddressBook.prototype.$id=function(){return this.id?AddressBook.$q.when(this.id):this.$futureAddressBookData.then(function(addressbook){return addressbook.id})},AddressBook.prototype.$selectedCount=function(){var count;return count=0,this.cards&&(count=_.filter(this.cards,function(card){return card.selected}).length),count},AddressBook.prototype.$startRefreshTimeout=function(){var _this=this;AddressBook.$refreshTimeout&&AddressBook.$timeout.cancel(AddressBook.$refreshTimeout),AddressBook.$Preferences.ready().then(function(){var refreshViewCheck=AddressBook.$Preferences.defaults.SOGoRefreshViewCheck;if(refreshViewCheck&&"manually"!=refreshViewCheck){var f=angular.bind(_this,AddressBook.prototype.$reload);AddressBook.$refreshTimeout=AddressBook.$timeout(f,1e3*refreshViewCheck.timeInterval())}})},AddressBook.prototype.$reload=function(){return this.$startRefreshTimeout(),this.$filter()},AddressBook.prototype.$filter=function(search,options,excludedCards){var _tLine truncated
//# sourceMappingURL=Contacts.services.js.map
Loaded 100 of 196 files, more files were not shown because too many files have changed in this diff. Show more