Merge branch 'master' into feature/addMissingStrings2

Conflicts:
	UI/AdministrationUI/English.lproj/Localizable.strings
	UI/PreferencesUI/English.lproj/Localizable.strings
	UI/Templates/PreferencesUI/UIxFilterEditor.wox
This commit is contained in:
Ludovic Marcotte
2015-12-03 11:16:17 -05:00
390 changed files with 57470 additions and 27697 deletions
@@ -15,3 +15,12 @@
"ACLs_description" = "<p>The Access Control Lists administration module allows to change the ACLs of each user's Calendars and Address books.</p><p>To modify the ACLs of a user's folder, type the name of the user in the search field at the top of the window and double-click on the desired folder.</p>";
"Name or Email" = "Name or Email";
/* Rights module: initial search message */
"Start a search to edit the rights" = "Start a search to edit the rights";
/* Rights module: Empty search result */
"No matching user" = "No matching user";
/* Rights module: no selection */
"No resource selected" = "No resource selected";
+1
View File
@@ -12,6 +12,7 @@ AdministrationUI_OBJC_FILES = \
AdministrationUIProduct.m \
\
UIxAdministration.m \
UIxAdministrationAclEditor.m \
UIxAdministrationFilterPanel.m
AdministrationUI_RESOURCE_FILES += \
+5
View File
@@ -46,6 +46,11 @@
[super dealloc];
}
- (NSString *) modulePath
{
return @"Administration";
}
- (BOOL) shouldTakeValuesFromRequest: (WORequest *) request
inContext: (WOContext*) context
{
@@ -0,0 +1,48 @@
/* UIxAdministrationAclEditor.h - this file is part of SOGo
*
* Copyright (C) 2006-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
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef UIXACLEDITOR_H
#define UIXACLEDITOR_H
#import <SOGoUI/UIxComponent.h>
@interface UIxAdministrationAclEditor : UIxComponent
{
BOOL prepared;
BOOL publishInFreeBusy;
NSArray *aclUsers;
NSArray *savedUIDs;
NSMutableDictionary *users;
NSString *currentUser;
NSString *defaultUserID;
}
- (NSArray *) aclsForObject;
- (void) setCurrentUser: (NSString *) newCurrentUser;
- (NSString *) currentUser;
- (NSString *) currentUserClass;
- (NSDictionary *) currentUserInfos;
- (NSString *) currentUserDisplayName;
- (BOOL) currentUserIsSubscribed;
- (BOOL) isPublicAccessEnabled;
@end
#endif /* UIXACLEDITOR_H */
@@ -0,0 +1,279 @@
/* UIxAdministrationAclEditor.m - this file is part of SOGo
*
* 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.
*/
#import <Foundation/NSArray.h>
#import <Foundation/NSValue.h>
#import <Foundation/NSDictionary.h>
#import <Foundation/NSEnumerator.h>
#import <Foundation/NSKeyValueCoding.h>
#import <NGObjWeb/SoSecurityManager.h>
#import <NGObjWeb/SoUser.h>
#import <NGObjWeb/WORequest.h>
#import <NGObjWeb/WOResponse.h>
#import <NGCards/iCalPerson.h>
#import <SOGo/NSArray+Utilities.h>
#import <SOGo/NSDictionary+Utilities.h>
#import <SOGo/SOGoContentObject.h>
#import <SOGo/SOGoGCSFolder.h>
#import <SOGo/SOGoPermissions.h>
#import <SOGo/SOGoSystemDefaults.h>
#import <SOGo/SOGoUser.h>
#import <SOGo/SOGoUserManager.h>
#import "UIxAdministrationAclEditor.h"
@implementation UIxAdministrationAclEditor
- (id) init
{
if ((self = [super init]))
{
aclUsers = nil;
prepared = NO;
publishInFreeBusy = NO;
users = [NSMutableDictionary new];
currentUser = nil;
defaultUserID = nil;
savedUIDs = nil;
}
return self;
}
- (void) dealloc
{
[savedUIDs release];
[users release];
[currentUser release];
[defaultUserID release];
[super dealloc];
}
- (NSArray *) aclsForObject
{
if (!aclUsers)
aclUsers = [[self clientObject] aclUsers];
return aclUsers;
}
- (NSString *) defaultUserID
{
if (!defaultUserID)
ASSIGN (defaultUserID, [[self clientObject] defaultUserID]);
return defaultUserID;
}
- (BOOL) canSubscribeUsers
{
return [[self clientObject]
respondsToSelector: @selector (subscribeUserOrGroup:reallyDo:response:)];
}
/**
* @api {get} /so/:username/:folderPath/acls List users with rights
* @apiVersion 1.0.0
* @apiName GetAcls
* @apiGroup Common
* @apiExample {curl} Example usage:
* curl -i http://localhost/SOGo/so/sogo1/Calendar/personal/acls
*
* @apiSuccess (Success 200) {Object[]} users List of users with ACL for the folder
* @apiSuccess (Success 200) {String} users.uid User ID
* @apiSuccess (Success 200) {String} users.userClass Either 'normal-user', 'normal-group' or 'public-access'
* @apiSuccess (Success 200) {Number} users.isSubscribed 1 if the user is subscribed to the folder
* @apiSuccess (Success 200) {String} [users.cn] User fullname
* @apiSuccess (Success 200) {String} [users.c_email] User main email address
*/
- (id <WOActionResults>) aclsAction
{
NSString *currentUID, *ownerLogin, *info;
NSDictionary *currentUserInfos;
NSMutableDictionary *userData;
id <WOActionResults> result;
NSEnumerator *aclsEnum;
if (!prepared)
{
ownerLogin = [[self clientObject] ownerInContext: context];
if (!defaultUserID)
ASSIGN (defaultUserID, [[self clientObject] defaultUserID]);
aclsEnum = [[self aclsForObject] objectEnumerator];
while ((currentUID = [aclsEnum nextObject]))
{
if (!([currentUID isEqualToString: ownerLogin]
|| [currentUID isEqualToString: defaultUserID]
|| [currentUID isEqualToString: @"anonymous"]))
{
// Set the current user in order to get information associated with it
[self setCurrentUser: currentUID];
// Build the object associated to the current UID
currentUserInfos = [self currentUserInfos];
userData = [NSMutableDictionary dictionaryWithObjectsAndKeys:
currentUser, @"uid",
[self currentUserClass], @"userClass",
[NSNumber numberWithBool: [self currentUserIsSubscribed]], @"isSubscribed",
nil];
if ((info = [currentUserInfos objectForKey: @"cn"]) && [info length])
[userData setObject: info forKey: @"cn"];
if ((info = [currentUserInfos objectForKey: @"c_email"]) && [info length])
[userData setObject: info forKey: @"c_email"];
[users setObject: userData forKey: currentUID];
}
}
// Add the 'Any authenticated' user
if ([self canSubscribeUsers])
{
userData = [NSDictionary dictionaryWithObjectsAndKeys:
@"<default>", @"uid",
[self labelForKey: @"Any Authenticated User"], @"cn",
@"public-user", @"userClass",
nil];
[users setObject: userData forKey: @"<default>"];
}
if ([self canSubscribeUsers] && [self isPublicAccessEnabled])
{
// Add the 'public access' user
userData = [NSDictionary dictionaryWithObjectsAndKeys:
@"anonymous", @"uid",
[self labelForKey: @"Public Access"], @"cn",
@"public-user", @"userClass",
nil];
[users setObject: userData forKey: @"anonymous"];
}
prepared = YES;
}
result = [self responseWithStatus: 200
andJSONRepresentation: [NSDictionary dictionaryWithObject: users forKey: @"users"]];
return result;
}
- (void) setCurrentUser: (NSString *) newCurrentUser
{
ASSIGN (currentUser, newCurrentUser);
}
- (NSString *) currentUser
{
return ([currentUser hasPrefix: @"@"]
? [currentUser substringFromIndex: 1]
: currentUser);
}
- (NSString *) currentUserClass
{
return ([currentUser hasPrefix: @"@"]
? @"normal-group"
: @"normal-user");
}
- (NSString *) currentUserDisplayName
{
NSDictionary *infos;
NSString *uid;
SOGoUserManager *um;
um = [SOGoUserManager sharedUserManager];
uid = [self currentUser];
infos = [um contactInfosForUserWithUIDorEmail: uid inDomain: [[context activeUser] domain]];
if (infos)
{
return [NSString stringWithFormat: @"%@ <%@>",
[infos objectForKey: @"cn"],
[infos objectForKey: @"c_email"]];
}
else
return uid;
}
- (NSDictionary *) currentUserInfos
{
SOGoUserManager *um;
um = [SOGoUserManager sharedUserManager];
return [um contactInfosForUserWithUIDorEmail: [self currentUser]];
}
- (BOOL) currentUserIsSubscribed
{
SOGoGCSFolder *folder;
folder = [self clientObject];
return ([folder respondsToSelector: @selector (userIsSubscriber:)]
&& [folder userIsSubscriber: currentUser]);
}
- (void) setUserUIDS: (NSString *) retainedUsers
{
if ([retainedUsers length] > 0)
{
savedUIDs = [retainedUsers componentsSeparatedByString: @","];
[savedUIDs retain];
}
else
savedUIDs = [NSArray new];
}
- (NSString *) folderID
{
return [[self clientObject] nameInContainer];
}
- (BOOL) shouldTakeValuesFromRequest: (WORequest *) request
inContext: (WOContext *) context
{
return ([[request method] isEqualToString: @"POST"]);
}
- (id <WOActionResults>) saveAclsAction
{
NSEnumerator *aclsEnum;
SOGoObject *clientObject;
NSString *currentUID, *ownerLogin;
clientObject = [self clientObject];
ownerLogin = [clientObject ownerInContext: context];
aclsEnum = [[self aclsForObject] objectEnumerator];
while ((currentUID = [[aclsEnum nextObject] objectForKey: @"c_uid"]))
if ([currentUID isEqualToString: ownerLogin]
|| [savedUIDs containsObject: currentUID])
[users removeObjectForKey: currentUID];
[clientObject removeAclsForUsers: [users allKeys]];
return [self jsCloseWithRefreshMethod: nil];
}
- (BOOL) isPublicAccessEnabled
{
return [[SOGoSystemDefaults sharedSystemDefaults] enablePublicAccess];
}
@end
+4
View File
@@ -15,6 +15,10 @@
protectedBy = "View";
pageName = "UIxAdministration";
};
UIxAdministrationAclEditor = {
protectedBy = "View";
pageName = "UIxAdministrationAclEditor";
};
};
};
};
+1 -8
View File
@@ -249,14 +249,7 @@
- (NSString *) commonLocalizableStrings
{
NSString *rc;
if (isPopup)
rc = @"";
else
rc = [NSString stringWithFormat: @"var clabels = %@;", [self _stringsForFramework: nil]];
return rc;
return [NSString stringWithFormat: @"var clabels = %@;", [self _stringsForFramework: nil]];
}
- (NSString *) productLocalizableStrings
+1 -1
View File
@@ -167,7 +167,7 @@
[self errorWithFormat:
@"not toolbar configuration found on SoObject: %@ (%@)",
[self clientObject], [[self clientObject] soClass]];
toolbarConfig = [[NSNull null] retain];
toolbarConfig = (NSArray *)[[NSNull null] retain];
return nil;
}
+3
View File
@@ -20,6 +20,7 @@
#import <Foundation/NSDictionary.h>
#import <Foundation/NSBundle.h>
#import <Foundation/NSKeyValueCoding.h>
#import <NGObjWeb/SoObjects.h>
#import <NGObjWeb/WOContext+SoObjects.h>
@@ -31,6 +32,8 @@
#import <SoObjects/SOGo/SOGoUser.h>
#import <SoObjects/SOGo/SOGoUserDefaults.h>
#import <NGExtensions/NSObject+Logs.h>
#import "WODirectAction+SOGo.h"
static SoProduct *commonProduct = nil;
@@ -44,6 +44,27 @@
"Copy To" = "Copy To";
"Add to:" = "Add to:";
/* Subheader of empty addressbook */
"No contact" = "No contact";
/* Subheader of system addressbook */
"Start a search to browse this address book" = "Start a search to browse this address book";
/* Number of contacts in addressbook; string is prefixed by number */
"contacts" = "contacts";
/* No contact matching search criteria */
"No matching contact" = "No matching contact";
/* Number of contacts matching search criteria; string is prefixed by number */
"matching contacts" = "matching contacts";
/* 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";
+2 -1
View File
@@ -23,7 +23,8 @@ ContactsUI_OBJC_FILES = \
UIxContactsListActions.m \
UIxContactFoldersView.m \
UIxContactFolderActions.m \
UIxContactFolderLinksTemplate.m
UIxContactFolderLinksTemplate.m \
UIxContactFolderProperties.m
ContactsUI_RESOURCE_FILES += \
product.plist \
+1 -1
View File
@@ -141,7 +141,7 @@
content = [NSMutableString string];
response = [context response];
[content appendFormat: [[self clientObject] contentAsString]];
[content appendFormat: @"%@", [[self clientObject] contentAsString]];
[response setHeader: @"text/plain; charset=utf-8"
forKey: @"content-type"];
[response appendContentString: content];
+9 -2
View File
@@ -349,7 +349,7 @@ static Class SOGoContactGCSEntryK = Nil;
NSMutableArray *units, *categories;
NSCalendarDate *date;
id o;
unsigned int i, year, month, day;
unsigned int i, year, month, day, seconds;
[card setNWithFamily: [attributes objectForKey: @"c_sn"]
given: [attributes objectForKey: @"c_givenname"]
@@ -357,8 +357,14 @@ static Class SOGoContactGCSEntryK = Nil;
[card setNickname: [attributes objectForKey: @"nickname"]];
[card setFn: [attributes objectForKey: @"c_cn"]];
[card setTitle: [attributes objectForKey: @"title"]];
[card setRole: [attributes objectForKey: @"role"]];
unsigned int seconds = [[NSString stringWithFormat: @"%@", [attributes objectForKey: @"birthday"]] intValue];
if ([attributes objectForKey: @"c_screenname"])
[[card uniqueChildWithTag: @"x-aim"]
setSingleValue: [attributes objectForKey: @"c_screenname"]
forKey: @""];
seconds = [[NSString stringWithFormat: @"%@", [attributes objectForKey: @"birthday"]] intValue];
if (seconds > 0)
{
date = [NSCalendarDate dateWithTimeIntervalSince1970: seconds];
@@ -519,6 +525,7 @@ static Class SOGoContactGCSEntryK = Nil;
* @apiParam {String} nickname Nickname
* @apiParam {String} c_sn Lastname
* @apiParam {String} c_cn Fullname
* @apiParam {String} c_screenname Screen Name (X-AIM for now)
* @apiParam {String} tz Timezone
* @apiParam {String} note Note
* @apiParam {String[]} allCategories All available categories
+6 -2
View File
@@ -28,10 +28,14 @@
#import <NGObjWeb/NSException+HTTP.h>
#import <NGObjWeb/WOContext.h>
#import <NGObjWeb/WOResponse.h>
#define COMPILING_NGOBJWEB 1 /* we want httpRequest for parsing multi-part
form data */
#import <NGObjWeb/WORequest.h>
#undef COMPILING_NGOBJWEB
#import <NGExtensions/NSString+misc.h>
#import <NGExtensions/NSNull+misc.h>
#import <NGExtensions/NGBase64Coding.h>
#import <NGMime/NGMimeMultipartBody.h>
#import <Contacts/SOGoContactObject.h>
#import <Contacts/SOGoContactFolder.h>
@@ -81,9 +85,9 @@
inContext: [self context]
acquire: NO];
if ([currentChild respondsToSelector: @selector (vCard)])
[content appendFormat: [[currentChild ldifRecord] ldifRecordAsString]];
[content appendFormat: @"%@", [[currentChild ldifRecord] ldifRecordAsString]];
else if ([currentChild respondsToSelector: @selector (vList)])
[content appendFormat: [[currentChild vList] ldifString]];
[content appendFormat: @"%@", [[currentChild vList] ldifString]];
[content appendString: @"\n"];
}
+32
View File
@@ -0,0 +1,32 @@
/* UIxContactFolderProperties.m - this file is part of SOGo
*
* Copyright (C) 2015 Inverse inc.
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#import <SOGoUI/UIxComponent.h>
@class NSString;
@class SOGoContactGCSFolder;
@interface UIxContactFolderProperties : UIxComponent
{
SOGoContactGCSFolder *addressbook;
}
@end
+84
View File
@@ -0,0 +1,84 @@
/* UIxContactFolderProperties.m - this file is part of SOGo
*
* Copyright (C) 2015 Inverse inc.
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#import <Foundation/NSDictionary.h>
#import <Foundation/NSEnumerator.h>
#import <Foundation/NSURL.h>
#import <Foundation/NSValue.h>
#import <NGObjWeb/WORequest.h>
#import <SOGo/NSString+Utilities.h>
#import <SOGo/SOGoUser.h>
#import <SOGo/SOGoUserSettings.h>
#import <SOGo/SOGoSystemDefaults.h>
#import <Contacts/SOGoContactGCSFolder.h>
#import "UIxContactFolderProperties.h"
@implementation UIxContactFolderProperties
- (id) init
{
if ((self = [super init]))
{
addressbook = [self clientObject];
}
return self;
}
- (void) dealloc
{
[super dealloc];
}
/**
* @api {post} /so/:username/Contacts/:addressbookId/save Save addressbook
* @apiDescription Save an addressbook's properties.
* @apiVersion 1.0.0
* @apiName PostSaveProperties
* @apiGroup AddressBook
*
* @apiParam {String} name Human readable name
* @apiParam {Number} synchronize 1 if we enable EAS synchronization for this addressbook
*/
- (WOResponse *) savePropertiesAction
{
WORequest *request;
NSDictionary *params;
id o, values;
request = [context request];
params = [[request contentAsString] objectFromJSONString];
o = [params objectForKey: @"name"];
if ([o isKindOfClass: [NSString class]])
[addressbook renameTo: o];
o = [params objectForKey: @"synchronize"];
if ([o isKindOfClass: [NSNumber class]])
[addressbook setSynchronize: [o boolValue]];
return [self responseWith204];
}
@end
+15 -1
View File
@@ -71,6 +71,11 @@ Class SOGoContactSourceFolderK, SOGoGCSFolderK;
return self;
}
- (NSString *) modulePath
{
return @"Contacts";
}
- (void) _setupContext
{
SOGoUser *activeUser;
@@ -291,7 +296,7 @@ Class SOGoContactSourceFolderK, SOGoGCSFolderK;
NSDictionary *folderAttrs;
id currentFolder;
BOOL objectCreator, objectEditor, objectEraser;
BOOL objectCreator, objectEditor, objectEraser, synchronize;
int max, i;
userLogin = [[context activeUser] login];
@@ -328,11 +333,20 @@ Class SOGoContactSourceFolderK, SOGoGCSFolderK;
[NSNumber numberWithBool: objectEditor], @"objectEditor",
[NSNumber numberWithBool: objectEraser], @"objectEraser", nil];
if ([currentFolder isKindOfClass: SOGoGCSFolderK])
synchronize = [currentFolder synchronize];
else
synchronize = NO;
if ([[currentFolder nameInContainer] isEqualToString: @"personal"])
synchronize = YES;
// 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",
[NSNumber numberWithBool: synchronize], @"synchronize",
owner, @"owner",
[NSNumber numberWithBool: [currentFolder isKindOfClass: SOGoGCSFolderK]], @"isEditable",
[NSNumber numberWithBool: [currentFolder isKindOfClass: SOGoContactSourceFolderK]
+8 -8
View File
@@ -1,18 +1,18 @@
/*
Copyright (C) 2004 SKYRIX Software AG
Copyright (C) 2005-2015 Inverse inc.
This file is part of OpenGroupware.org.
OGo is free software; you can redistribute it and/or modify it under
This file is part of SOGo.
SOGo 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
SOGo 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
@@ -35,7 +35,7 @@
NSMutableArray *photosURL;
}
- (NSString *) fullName;
//- (NSString *) fullName;
- (NSArray *) orgUnits;
- (NSString *) photoURL;
+414 -410
View File
@@ -1,5 +1,4 @@
/*
Copyright (C) 2004 SKYRIX Software AG
Copyright (C) 2005-2015 Inverse inc.
This file is part of SOGo.
@@ -69,70 +68,70 @@
/* accessors */
- (NSString *) _cardStringWithLabel: (NSString *) label
value: (NSString *) value
byEscapingHTMLString: (BOOL) escapeHTML
asLinkScheme: (NSString *) scheme
withLinkAttributes: (NSString *) attrs
{
NSMutableString *cardString;
// - (NSString *) _cardStringWithLabel: (NSString *) label
// value: (NSString *) value
// byEscapingHTMLString: (BOOL) escapeHTML
// asLinkScheme: (NSString *) scheme
// withLinkAttributes: (NSString *) attrs
// {
// NSMutableString *cardString;
cardString = [NSMutableString stringWithCapacity: 80];
value = [value stringByReplacingString: @"\r" withString: @""];
if ([value length] > 0)
{
if (escapeHTML)
value = [value stringByEscapingHTMLString];
if ([scheme length] > 0)
value = [NSString stringWithFormat: @"<a href=\"%@%@\" %@>%@</a>", scheme, value, attrs, value];
// cardString = [NSMutableString stringWithCapacity: 80];
// value = [value stringByReplacingString: @"\r" withString: @""];
// if ([value length] > 0)
// {
// if (escapeHTML)
// value = [value stringByEscapingHTMLString];
// if ([scheme length] > 0)
// value = [NSString stringWithFormat: @"<a href=\"%@%@\" %@>%@</a>", scheme, value, attrs, value];
if (label)
[cardString appendFormat: @"<dt>%@</dt><dd>%@</dd>\n",
[self labelForKey: label], value];
else
[cardString appendFormat: @"<dt></dt><dd>%@</dd>\n", value];
}
// if (label)
// [cardString appendFormat: @"<dt>%@</dt><dd>%@</dd>\n",
// [self labelForKey: label], value];
// else
// [cardString appendFormat: @"<dt></dt><dd>%@</dd>\n", value];
// }
return cardString;
}
// return cardString;
// }
- (NSString *) _cardStringWithLabel: (NSString *) label
value: (NSString *) value
{
return [self _cardStringWithLabel: label
value: value
byEscapingHTMLString: YES
asLinkScheme: nil
withLinkAttributes: nil];
}
// - (NSString *) _cardStringWithLabel: (NSString *) label
// value: (NSString *) value
// {
// return [self _cardStringWithLabel: label
// value: value
// byEscapingHTMLString: YES
// asLinkScheme: nil
// withLinkAttributes: nil];
// }
- (NSString *) _cardStringWithLabel: (NSString *) label
value: (NSString *) value
asLinkScheme: (NSString *) scheme
{
return [self _cardStringWithLabel: label
value: value
byEscapingHTMLString: YES
asLinkScheme: scheme
withLinkAttributes: nil];
}
// - (NSString *) _cardStringWithLabel: (NSString *) label
// value: (NSString *) value
// asLinkScheme: (NSString *) scheme
// {
// return [self _cardStringWithLabel: label
// value: value
// byEscapingHTMLString: YES
// asLinkScheme: scheme
// withLinkAttributes: nil];
// }
- (NSString *) displayName
{
return [self _cardStringWithLabel: @"Display Name:"
value: [card fn]];
}
// - (NSString *) displayName
// {
// return [self _cardStringWithLabel: @"Display Name:"
// value: [card fn]];
// }
- (NSString *) nickName
{
return [self _cardStringWithLabel: @"Nickname:"
value: [card nickname]];
}
// - (NSString *) nickName
// {
// return [self _cardStringWithLabel: @"Nickname:"
// value: [card nickname]];
// }
- (NSString *) fullName
{
return [card fullName];
}
// - (NSString *) fullName
// {
// return [card fullName];
// }
- (NSArray *) _languageContactsCategories
{
@@ -173,345 +172,345 @@
return cats;
}
- (NSString *) primaryEmail
{
NSString *email, *fn, *attrs;
// - (NSString *) primaryEmail
// {
// NSString *email, *fn, *attrs;
email = [card preferredEMail];
if ([email length] > 0)
{
fn = [card fn];
if ([fn length] > 0)
attrs = [NSString stringWithFormat: @"%@ <%@>", fn, email];
else
attrs = email;
attrs = [attrs stringByReplacingString: @"'" withString: @"\\'"];
attrs = [attrs stringByReplacingString: @"\"" withString: @"\\\""];
attrs = [NSString stringWithFormat: @"onclick=\"return openMailTo('%@');\"", attrs];
}
else
{
attrs = nil;
}
// email = [card preferredEMail];
// if ([email length] > 0)
// {
// fn = [card fn];
// if ([fn length] > 0)
// attrs = [NSString stringWithFormat: @"%@ <%@>", fn, email];
// else
// attrs = email;
// attrs = [attrs stringByReplacingString: @"'" withString: @"\\'"];
// attrs = [attrs stringByReplacingString: @"\"" withString: @"\\\""];
// attrs = [NSString stringWithFormat: @"onclick=\"return openMailTo('%@');\"", attrs];
// }
// else
// {
// attrs = nil;
// }
return [self _cardStringWithLabel: @"Email:"
value: email
byEscapingHTMLString: YES
asLinkScheme: @"mailto:"
withLinkAttributes: attrs];
}
// return [self _cardStringWithLabel: @"Email:"
// value: email
// byEscapingHTMLString: YES
// asLinkScheme: @"mailto:"
// withLinkAttributes: attrs];
// }
- (NSArray *) secondaryEmails
{
NSMutableArray *secondaryEmails;
NSString *email, *fn, *attrs;
NSArray *emails;
// - (NSArray *) secondaryEmails
// {
// NSMutableArray *secondaryEmails;
// NSString *email, *fn, *attrs;
// NSArray *emails;
emails = [card secondaryEmails];
secondaryEmails = [NSMutableArray array];
attrs = nil;
// emails = [card secondaryEmails];
// secondaryEmails = [NSMutableArray array];
// attrs = nil;
// We might not have a preferred item but rather something like this:
// EMAIL;TYPE=work:dd@ee.com
// EMAIL;TYPE=home:ff@gg.com
//
// or:
//
// EMAIL;TYPE=INTERNET:a@a.com
// EMAIL;TYPE=INTERNET,HOME:b@b.com
//
// In this case, we always return the entry NOT matching the primaryEmail
if ([emails count] > 0)
{
int i;
// // We might not have a preferred item but rather something like this:
// // EMAIL;TYPE=work:dd@ee.com
// // EMAIL;TYPE=home:ff@gg.com
// //
// // or:
// //
// // EMAIL;TYPE=INTERNET:a@a.com
// // EMAIL;TYPE=INTERNET,HOME:b@b.com
// //
// // In this case, we always return the entry NOT matching the primaryEmail
// if ([emails count] > 0)
// {
// int i;
for (i = 0; i < [emails count]; i++)
{
email = [[emails objectAtIndex: i] flattenedValuesForKey: @""];
if ([email length])
{
fn = [card fn];
if ([fn length])
attrs = [NSString stringWithFormat: @"%@ <%@>", fn, email];
else
attrs = email;
attrs = [attrs stringByReplacingString: @"'" withString: @"\\'"];
attrs = [attrs stringByReplacingString: @"\"" withString: @"\\\""];
attrs = [NSString stringWithFormat: @"onclick=\"return openMailTo('%@');\"", attrs];
// for (i = 0; i < [emails count]; i++)
// {
// email = [[emails objectAtIndex: i] flattenedValuesForKey: @""];
// if ([email length])
// {
// fn = [card fn];
// if ([fn length])
// attrs = [NSString stringWithFormat: @"%@ <%@>", fn, email];
// else
// attrs = email;
// attrs = [attrs stringByReplacingString: @"'" withString: @"\\'"];
// attrs = [attrs stringByReplacingString: @"\"" withString: @"\\\""];
// attrs = [NSString stringWithFormat: @"onclick=\"return openMailTo('%@');\"", attrs];
[secondaryEmails addObject: [self _cardStringWithLabel: nil
value: email
byEscapingHTMLString: YES
asLinkScheme: @"mailto:"
withLinkAttributes: attrs]];
}
}
}
else
{
[secondaryEmails addObject: [self _cardStringWithLabel: nil
value: nil]];
}
// [secondaryEmails addObject: [self _cardStringWithLabel: nil
// value: email
// byEscapingHTMLString: YES
// asLinkScheme: @"mailto:"
// withLinkAttributes: attrs]];
// }
// }
// }
// else
// {
// [secondaryEmails addObject: [self _cardStringWithLabel: nil
// value: nil]];
// }
return secondaryEmails;
}
// return secondaryEmails;
// }
- (NSString *) screenName
{
NSString *screenName;
// - (NSString *) screenName
// {
// NSString *screenName;
screenName = [[card uniqueChildWithTag: @"x-aim"] flattenedValuesForKey: @""];
// screenName = [[card uniqueChildWithTag: @"x-aim"] flattenedValuesForKey: @""];
return [self _cardStringWithLabel: @"Screen Name:"
value: screenName
asLinkScheme: @"aim:goim?screenname="];
}
// return [self _cardStringWithLabel: @"Screen Name:"
// value: screenName
// asLinkScheme: @"aim:goim?screenname="];
// }
- (NSString *) preferredTel
{
return [self _cardStringWithLabel: @"Phone Number:"
value: [card preferredTel] asLinkScheme: @"tel:"];
}
// - (NSString *) preferredTel
// {
// return [self _cardStringWithLabel: @"Phone Number:"
// value: [card preferredTel] asLinkScheme: @"tel:"];
// }
- (NSString *) preferredAddress
{
return @"";
}
// - (NSString *) preferredAddress
// {
// return @"";
// }
- (BOOL) hasTelephones
{
if (!phones)
phones = [card childrenWithTag: @"tel"];
// - (BOOL) hasTelephones
// {
// if (!phones)
// phones = [card childrenWithTag: @"tel"];
return ([phones count] > 0);
}
// return ([phones count] > 0);
// }
- (NSString *) workPhone
{
// We do this (exclude FAX) in order to avoid setting the WORK number as the FAX
// one if we do see the FAX field BEFORE the WORK number.
return [self _cardStringWithLabel: @"Work:" value: [card workPhone] asLinkScheme: @"tel:"];
}
// - (NSString *) workPhone
// {
// // We do this (exclude FAX) in order to avoid setting the WORK number as the FAX
// // one if we do see the FAX field BEFORE the WORK number.
// return [self _cardStringWithLabel: @"Work:" value: [card workPhone] asLinkScheme: @"tel:"];
// }
- (NSString *) homePhone
{
return [self _cardStringWithLabel: @"Home:" value: [card homePhone] asLinkScheme: @"tel:"];
}
// - (NSString *) homePhone
// {
// return [self _cardStringWithLabel: @"Home:" value: [card homePhone] asLinkScheme: @"tel:"];
// }
- (NSString *) fax
{
return [self _cardStringWithLabel: @"Fax:" value: [card fax] asLinkScheme: @"tel:"];
}
// - (NSString *) fax
// {
// return [self _cardStringWithLabel: @"Fax:" value: [card fax] asLinkScheme: @"tel:"];
// }
- (NSString *) mobile
{
return [self _cardStringWithLabel: @"Mobile:" value: [card mobile] asLinkScheme: @"tel:"];
}
// - (NSString *) mobile
// {
// return [self _cardStringWithLabel: @"Mobile:" value: [card mobile] asLinkScheme: @"tel:"];
// }
- (NSString *) pager
{
return [self _cardStringWithLabel: @"Pager:" value: [card pager] asLinkScheme: @"tel:"];
}
// - (NSString *) pager
// {
// return [self _cardStringWithLabel: @"Pager:" value: [card pager] asLinkScheme: @"tel:"];
// }
- (BOOL) hasHomeInfos
{
BOOL result;
NSArray *elements;
// - (BOOL) hasHomeInfos
// {
// BOOL result;
// NSArray *elements;
elements = [card childrenWithTag: @"adr"
andAttribute: @"type"
havingValue: @"home"];
if ([elements count] > 0)
{
result = YES;
homeAdr = [elements objectAtIndex: 0];
}
else
result = ([[card childrenWithTag: @"url"
andAttribute: @"type"
havingValue: @"home"] count] > 0);
// elements = [card childrenWithTag: @"adr"
// andAttribute: @"type"
// havingValue: @"home"];
// if ([elements count] > 0)
// {
// result = YES;
// homeAdr = [elements objectAtIndex: 0];
// }
// else
// result = ([[card childrenWithTag: @"url"
// andAttribute: @"type"
// havingValue: @"home"] count] > 0);
return result;
}
// return result;
// }
- (NSString *) homePobox
{
return [self _cardStringWithLabel: nil
value: [homeAdr flattenedValueAtIndex: 0
forKey: @""]];
}
// - (NSString *) homePobox
// {
// return [self _cardStringWithLabel: nil
// value: [homeAdr flattenedValueAtIndex: 0
// forKey: @""]];
// }
- (NSString *) homeExtendedAddress
{
return [self _cardStringWithLabel: nil
value: [homeAdr flattenedValueAtIndex: 1
forKey: @""]];
}
// - (NSString *) homeExtendedAddress
// {
// return [self _cardStringWithLabel: nil
// value: [homeAdr flattenedValueAtIndex: 1
// forKey: @""]];
// }
- (NSString *) homeStreetAddress
{
return [self _cardStringWithLabel: nil
value: [homeAdr flattenedValueAtIndex: 2
forKey: @""]];
}
// - (NSString *) homeStreetAddress
// {
// return [self _cardStringWithLabel: nil
// value: [homeAdr flattenedValueAtIndex: 2
// forKey: @""]];
// }
- (NSString *) homeCityAndProv
{
NSString *city, *prov;
NSMutableString *data;
// - (NSString *) homeCityAndProv
// {
// NSString *city, *prov;
// NSMutableString *data;
city = [homeAdr flattenedValueAtIndex: 3 forKey: @""];
prov = [homeAdr flattenedValueAtIndex: 4 forKey: @""];
// city = [homeAdr flattenedValueAtIndex: 3 forKey: @""];
// prov = [homeAdr flattenedValueAtIndex: 4 forKey: @""];
data = [NSMutableString string];
[data appendString: city];
if ([city length] > 0 && [prov length] > 0)
[data appendString: @", "];
[data appendString: prov];
// data = [NSMutableString string];
// [data appendString: city];
// if ([city length] > 0 && [prov length] > 0)
// [data appendString: @", "];
// [data appendString: prov];
return [self _cardStringWithLabel: nil value: data];
}
// return [self _cardStringWithLabel: nil value: data];
// }
- (NSString *) homePostalCodeAndCountry
{
NSString *postalCode, *country;
NSMutableString *data;
// - (NSString *) homePostalCodeAndCountry
// {
// NSString *postalCode, *country;
// NSMutableString *data;
postalCode = [homeAdr flattenedValueAtIndex: 5 forKey: @""];
country = [homeAdr flattenedValueAtIndex: 6 forKey: @""];
// postalCode = [homeAdr flattenedValueAtIndex: 5 forKey: @""];
// country = [homeAdr flattenedValueAtIndex: 6 forKey: @""];
data = [NSMutableString string];
[data appendString: postalCode];
if ([postalCode length] > 0 && [country length] > 0)
[data appendFormat: @", ", country];
[data appendString: country];
// data = [NSMutableString string];
// [data appendString: postalCode];
// if ([postalCode length] > 0 && [country length] > 0)
// [data appendFormat: @", "];
// [data appendString: country];
return [self _cardStringWithLabel: nil value: data];
}
// return [self _cardStringWithLabel: nil value: data];
// }
- (NSString *) _formattedURL: (NSString *) url
{
NSRange schemaR;
NSString *schema, *data;
// - (NSString *) _formattedURL: (NSString *) url
// {
// NSRange schemaR;
// NSString *schema, *data;
if ([url length] > 0)
{
schemaR = [url rangeOfString: @"://"];
if (schemaR.length > 0)
{
schema = [url substringToIndex: schemaR.location + schemaR.length];
data = [url substringFromIndex: schemaR.location + schemaR.length];
}
else
{
schema = @"http://";
data = url;
}
}
else
{
schema = nil;
data = nil;
}
// if ([url length] > 0)
// {
// schemaR = [url rangeOfString: @"://"];
// if (schemaR.length > 0)
// {
// schema = [url substringToIndex: schemaR.location + schemaR.length];
// data = [url substringFromIndex: schemaR.location + schemaR.length];
// }
// else
// {
// schema = @"http://";
// data = url;
// }
// }
// else
// {
// schema = nil;
// data = nil;
// }
return [self _cardStringWithLabel: nil
value: data
byEscapingHTMLString: YES
asLinkScheme: schema
withLinkAttributes: @"target=\"_blank\""];
}
// return [self _cardStringWithLabel: nil
// value: data
// byEscapingHTMLString: YES
// asLinkScheme: schema
// withLinkAttributes: @"target=\"_blank\""];
// }
- (NSString *) _urlOfType: (NSString *) aType
{
NSArray *elements;
NSString *url;
// - (NSString *) _urlOfType: (NSString *) aType
// {
// NSArray *elements;
// NSString *url;
elements = [card childrenWithTag: @"url"
andAttribute: @"type"
havingValue: aType];
if ([elements count] > 0)
url = [[elements objectAtIndex: 0] flattenedValuesForKey: @""];
else
url = nil;
// elements = [card childrenWithTag: @"url"
// andAttribute: @"type"
// havingValue: aType];
// if ([elements count] > 0)
// url = [[elements objectAtIndex: 0] flattenedValuesForKey: @""];
// else
// url = nil;
return [self _formattedURL: url];
}
// return [self _formattedURL: url];
// }
- (NSString *) homeUrl
{
NSString *s;
// - (NSString *) homeUrl
// {
// NSString *s;
s = [self _urlOfType: @"home"];
// s = [self _urlOfType: @"home"];
if (!s || [s length] == 0)
{
NSArray *elements;
NSString *workURL;
int i;
// if (!s || [s length] == 0)
// {
// NSArray *elements;
// NSString *workURL;
// int i;
elements = [card childrenWithTag: @"url"
andAttribute: @"type"
havingValue: @"work"];
workURL = nil;
// elements = [card childrenWithTag: @"url"
// andAttribute: @"type"
// havingValue: @"work"];
// workURL = nil;
if ([elements count] > 0)
workURL = [[elements objectAtIndex: 0] flattenedValuesForKey: @""];
// if ([elements count] > 0)
// workURL = [[elements objectAtIndex: 0] flattenedValuesForKey: @""];
elements = [card childrenWithTag: @"url"];
// elements = [card childrenWithTag: @"url"];
if (workURL && [elements count] > 1)
{
for (i = 0; i < [elements count]; i++)
{
if ([[[elements objectAtIndex: i] flattenedValuesForKey: @""]
caseInsensitiveCompare: workURL] != NSOrderedSame)
{
s = [[elements objectAtIndex: i] flattenedValuesForKey: @""];
break;
}
}
// if (workURL && [elements count] > 1)
// {
// for (i = 0; i < [elements count]; i++)
// {
// if ([[[elements objectAtIndex: i] flattenedValuesForKey: @""]
// caseInsensitiveCompare: workURL] != NSOrderedSame)
// {
// s = [[elements objectAtIndex: i] flattenedValuesForKey: @""];
// break;
// }
// }
}
else if (!workURL && [elements count] > 0)
{
s = [[elements objectAtIndex: 0] flattenedValuesForKey: @""];
}
// }
// else if (!workURL && [elements count] > 0)
// {
// s = [[elements objectAtIndex: 0] flattenedValuesForKey: @""];
// }
if (s && [s length] > 0)
s = [self _formattedURL: s];
}
// if (s && [s length] > 0)
// s = [self _formattedURL: s];
// }
return s;
}
// return s;
// }
- (BOOL) hasWorkInfos
{
BOOL result;
NSArray *elements;
// - (BOOL) hasWorkInfos
// {
// BOOL result;
// NSArray *elements;
elements = [card childrenWithTag: @"adr"
andAttribute: @"type"
havingValue: @"work"];
if ([elements count] > 0)
{
result = YES;
workAdr = [elements objectAtIndex: 0];
}
else
result = (([[card childrenWithTag: @"url"
andAttribute: @"type"
havingValue: @"work"] count] > 0)
|| [[card childrenWithTag: @"org"] count] > 0);
// elements = [card childrenWithTag: @"adr"
// andAttribute: @"type"
// havingValue: @"work"];
// if ([elements count] > 0)
// {
// result = YES;
// workAdr = [elements objectAtIndex: 0];
// }
// else
// result = (([[card childrenWithTag: @"url"
// andAttribute: @"type"
// havingValue: @"work"] count] > 0)
// || [[card childrenWithTag: @"org"] count] > 0);
return result;
}
// return result;
// }
- (NSString *) workTitle
{
return [self _cardStringWithLabel: nil value: [card title]];
}
// - (NSString *) workTitle
// {
// return [self _cardStringWithLabel: nil value: [card title]];
// }
- (NSArray *) orgUnits
{
@@ -608,65 +607,65 @@
return addresses;
}
- (NSString *) workService
{
NSMutableArray *orgServices;
NSArray *values;
CardElement *org;
NSString *service, *services;
NSUInteger count, max;
// - (NSString *) workService
// {
// NSMutableArray *orgServices;
// NSArray *values;
// CardElement *org;
// NSString *service, *services;
// NSUInteger count, max;
org = [card org];
values = [org valuesForKey: @""];
max = [values count];
if (max > 1)
{
orgServices = [NSMutableArray arrayWithCapacity: max];
for (count = 1; count < max; count++)
{
service = [org flattenedValueAtIndex: count forKey: @""];
if ([service length] > 0)
[orgServices addObject: service];
}
// org = [card org];
// values = [org valuesForKey: @""];
// max = [values count];
// if (max > 1)
// {
// orgServices = [NSMutableArray arrayWithCapacity: max];
// for (count = 1; count < max; count++)
// {
// service = [org flattenedValueAtIndex: count forKey: @""];
// if ([service length] > 0)
// [orgServices addObject: service];
// }
services = [orgServices componentsJoinedByString: @", "];
}
else
services = nil;
// services = [orgServices componentsJoinedByString: @", "];
// }
// else
// services = nil;
return [self _cardStringWithLabel: nil value: services];
}
// return [self _cardStringWithLabel: nil value: services];
// }
- (NSString *) workUrl
{
return [self _urlOfType: @"work"];
}
// - (NSString *) workUrl
// {
// return [self _urlOfType: @"work"];
// }
- (BOOL) hasOtherInfos
{
return ([[card note] length] > 0
|| [[card bday] length] > 0
|| [[card tz] length] > 0);
}
// - (BOOL) hasOtherInfos
// {
// return ([[card note] length] > 0
// || [[card bday] length] > 0
// || [[card tz] length] > 0);
// }
- (NSString *) bday
{
SOGoDateFormatter *dateFormatter;
NSCalendarDate *date;
NSString *bday;
// - (NSString *) bday
// {
// SOGoDateFormatter *dateFormatter;
// NSCalendarDate *date;
// NSString *bday;
date = [card birthday];
bday = nil;
// date = [card birthday];
// bday = nil;
if (date)
{
dateFormatter = [[[self context] activeUser] dateFormatterInContext: context];
bday = [dateFormatter formattedDate: date];
}
// if (date)
// {
// dateFormatter = [[[self context] activeUser] dateFormatterInContext: context];
// bday = [dateFormatter formattedDate: date];
// }
return bday;
//return [self _cardStringWithLabel: @"Birthday:" value: bday];
}
// return bday;
// //return [self _cardStringWithLabel: @"Birthday:" value: bday];
// }
// - (NSString *) tz
// {
@@ -693,29 +692,29 @@
/* hrefs */
- (NSString *) completeHrefForMethod: (NSString *) _method
withParameter: (NSString *) _param
forKey: (NSString *) _key
{
NSString *href;
// - (NSString *) completeHrefForMethod: (NSString *) _method
// withParameter: (NSString *) _param
// forKey: (NSString *) _key
// {
// NSString *href;
[self setQueryParameter:_param forKey:_key];
href = [self completeHrefForMethod:[self ownMethodName]];
[self setQueryParameter:nil forKey:_key];
// [self setQueryParameter:_param forKey:_key];
// href = [self completeHrefForMethod:[self ownMethodName]];
// [self setQueryParameter:nil forKey:_key];
return href;
}
// return href;
// }
- (NSString *)attributesTabLink {
return [self completeHrefForMethod:[self ownMethodName]
withParameter:@"attributes"
forKey:@"tab"];
}
- (NSString *)debugTabLink {
return [self completeHrefForMethod:[self ownMethodName]
withParameter:@"debug"
forKey:@"tab"];
}
// - (NSString *)attributesTabLink {
// return [self completeHrefForMethod:[self ownMethodName]
// withParameter:@"attributes"
// forKey:@"tab"];
// }
// - (NSString *)debugTabLink {
// return [self completeHrefForMethod:[self ownMethodName]
// withParameter:@"debug"
// forKey:@"tab"];
// }
/* action */
@@ -751,6 +750,7 @@
* @apiSuccess (Success 200) {String} [nickname] Nickname
* @apiSuccess (Success 200) {String} [c_sn] Lastname
* @apiSuccess (Success 200) {String} [c_fn] Fullname
* @apiSuccess (Success 200) {String} [c_screenname] Screen Name (X-AIM for now)
* @apiSuccess (Success 200) {String} [tz] Timezone
* @apiSuccess (Success 200) {String} [note] Note
* @apiSuccess (Success 200) {String[]} allCategories All available categories
@@ -812,6 +812,10 @@
if ([firstName length] > 0)
[data setObject: firstName forKey: @"c_givenname"];
}
o = [[card uniqueChildWithTag: @"x-aim"] flattenedValuesForKey: @""];
if ([o length]) [data setObject: o forKey: @"c_screenname"];
o = [card nickname];
if (o) [data setObject: o forKey: @"nickname"];
o = [card title];
+9 -5
View File
@@ -136,6 +136,15 @@
protectedBy = "View";
pageName = "UIxContactFolderLinksTemplate";
};
properties = {
protectedBy = "Access Contents Information";
pageName = "UIxContactFolderProperties";
};
save = {
protectedBy = "Access Contents Information";
pageName = "UIxContactFolderProperties";
actionName = "saveProperties";
};
};
};
@@ -157,11 +166,6 @@
pageName = "UIxContactEditor";
actionName = "new";
};
save = {
protectedBy = "Change Permissions";
actionClass = "UIxFolderActions";
actionName = "renameFolder";
};
mailer-contacts = {
protectedBy = "<public>";
pageName = "UIxContactFoldersView";
+8 -8
View File
@@ -161,10 +161,10 @@ static NSData* _sanitizeContent(NSData *theData)
if (i < len-5)
{
if ((*bytes == '<') &&
(*(bytes+1) == 'm' || *(bytes+2) == 'M') &&
(*(bytes+2) == 'e' || *(bytes+3) == 'E') &&
(*(bytes+3) == 't' || *(bytes+4) == 'T') &&
(*(bytes+4) == 'a' || *(bytes+5) == 'A') &&
(*(bytes+1) == 'm' || *(bytes+1) == 'M') &&
(*(bytes+2) == 'e' || *(bytes+2) == 'E') &&
(*(bytes+3) == 't' || *(bytes+3) == 'T') &&
(*(bytes+4) == 'a' || *(bytes+4) == 'A') &&
(*(bytes+5) == ' '))
in_meta = YES;
}
@@ -551,9 +551,9 @@ static NSData* _sanitizeContent(NSData *theData)
else
skipAttribute = YES;
}
else if ([name isEqualToString: @"background"] ||
else if (([name isEqualToString: @"background"] ||
([name isEqualToString: @"data"]
|| [name isEqualToString: @"classid"])
|| [name isEqualToString: @"classid"]))
&& [lowerName isEqualToString: @"object"])
{
value = [_attributes valueAtIndex: count];
@@ -741,7 +741,7 @@ static NSData* _sanitizeContent(NSData *theData)
/* SaxLexicalHandler */
- (void) comment: (unichar *) _chars
length: (NSUInteger) _len
length: (int) _len
{
showWhoWeAre();
if (inStyle)
@@ -807,7 +807,7 @@ static NSData* _sanitizeContent(NSData *theData)
}
[dump appendFormat: @"--- end ---\n"];
NSLog(dump);
NSLog(@"%@", dump);
[dump release];
}
@@ -46,6 +46,7 @@
#import <Mailer/SOGoMailObject.h>
#import <SOGo/SOGoParentFolder.h>
#import <SOGo/SOGoUser.h>
#import <SOGo/NSString+Utilities.h>
#import <Mailer/SOGoMailBodyPart.h>
#import "UIxMailPartICalActions.h"
@@ -228,7 +228,7 @@
info = [parts objectAtIndex: i];
viewer = [[[self context] mailRenderingContext] viewerForBodyInfo: info];
[viewer setBodyInfo: info];
[viewer setPartPath: [[self contentPartPath] arrayByAddingObject: [NSString stringWithFormat: @"%d", i+1]]];
[viewer setPartPath: [[self contentPartPath] arrayByAddingObject: [NSString stringWithFormat: @"%d", (int)i+1]]];
[renderedParts addObject: [viewer renderedPart]];
}
}
+1 -1
View File
@@ -33,7 +33,7 @@
- (void) setChildInfo: (id) _info;
- (id) childInfo;
- (void) setChildIndex: (unsigned int) _index;
- (void) setChildIndex: (NSUInteger) _index;
- (id) childPartPath;
+6 -1
View File
@@ -61,7 +61,7 @@
return [NSString stringWithFormat: @"%u",
(unsigned int) ([self childIndex] + 1)];
char buf[8];
sprintf(buf, "%d", [self childIndex] + 1);
sprintf(buf, "%d", (int)[self childIndex] + 1);
return [NSString stringWithCString:buf];
}
@@ -87,6 +87,7 @@
id info, viewer;
NSArray *parts;
NSMutableArray *renderedParts;
NSString *contentType;
NSUInteger i, max;
parts = [[self bodyInfo] objectForKey: @"parts"];
@@ -102,9 +103,13 @@
[viewer setPartPath: [self childPartPath]];
[renderedParts addObject: [viewer renderedPart]];
}
contentType = [NSString stringWithFormat: @"%@/%@",
[[self bodyInfo] objectForKey: @"type"],
[[self bodyInfo] objectForKey: @"subtype"]];
return [NSDictionary dictionaryWithObjectsAndKeys:
[self className], @"type",
contentType, @"contentType",
renderedParts, @"content",
nil];
}
+1 -3
View File
@@ -1,8 +1,6 @@
/* UIxMailPartTextViewer.h - this file is part of $PROJECT_NAME_HERE$
*
* Copyright (C) 2006 Inverse inc.
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
* 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
+19 -20
View File
@@ -1,23 +1,22 @@
/*
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.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.
*/
/*
UIxMailPartTextViewer
+1 -1
View File
@@ -287,7 +287,7 @@
if ([filename length])
// We replace any slash by a dash since Apache won't allow encoded slashes by default.
// See http://httpd.apache.org/docs/2.2/mod/core.html#allowencodedslashes
filename = [filename stringByReplacingString: @"/" withString: @"-"];
filename = (NSMutableString *)[filename stringByReplacingString: @"/" withString: @"-"];
else
[filename appendFormat: @"%@-%@",
[self labelForKey: @"Untitled"],
@@ -65,6 +65,9 @@
"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";
@@ -228,6 +231,9 @@
"Delete Message" = "Delete Message";
"Delete Selected Messages" = "Delete Selected Messages";
/* Number of selected messages in list */
"selected" = "selected";
"This Folder" = "This Folder";
/* Label popup menu */
+1 -1
View File
@@ -639,6 +639,7 @@ static NSArray *infoKeys = nil;
co = [self clientObject];
[co fetchInfo];
[co setIsHTML: isHTML];
if ([[mimeType type] isEqualToString: @"multipart"])
{
@@ -648,7 +649,6 @@ static NSArray *infoKeys = nil;
{
info = [self infoFromRequest];
[co setHeaders: info];
[co setIsHTML: isHTML];
[co setText: (isHTML ? [NSString stringWithFormat: @"<html>%@</html>", text] : text)];;
error = [co storeInfo];
}
+10 -3
View File
@@ -156,7 +156,7 @@
}
else
{
newKeyForMsgUIDs = [[NSString stringWithFormat:@"/%@/folder%@", currentAccount, newFolderName] asCSSIdentifier];
newKeyForMsgUIDs = [NSString stringWithFormat:@"/%@/folder%@", [currentAccount asCSSIdentifier], [newFolderName asCSSIdentifier]];
error = [co renameTo: newFolderName];
if (error)
{
@@ -451,7 +451,7 @@
NSMutableDictionary *moduleSettings, *threadsCollapsed;
NSMutableArray *mailboxThreadsCollapsed;
NSString *destinationFolder;
SOGoUserSettings *us;
SOGoUserSettings *us=nil;
WOResponse *response;
NSDictionary *data;
SOGoMailFolder *co;
@@ -739,6 +739,7 @@
NSDictionary *content, *result;
BOOL addOrRemove;
NGImap4Client *client;
id flag;
int i;
@@ -751,7 +752,13 @@
// We unescape our flags
for (i = [flags count]-1; i >= 0; i--)
[flags replaceObjectAtIndex: i withObject: [[flags objectAtIndex: i] fromCSSIdentifier]];
{
flag = [flags objectAtIndex: i];
if ([flag isKindOfClass: [NSString class]])
[flags replaceObjectAtIndex: i withObject: [flag fromCSSIdentifier]];
else
[flags removeObjectAtIndex: i];
}
co = [self clientObject];
client = [[co imap4Connection] client];
+42 -15
View File
@@ -164,13 +164,15 @@
//
// Sometimes, the MUAs don't send over the string in () so we ignore it.
//
- (NSString *) messagePriority
- (NSDictionary *) messagePriority
{
NSString *result;
NSUInteger priority;
NSString *description;
NSData *data;
data = [message objectForKey: @"header"];
result = @"";
priority = 3;
description = [self labelForKey: @"normal" inContext: context];
if (data)
{
@@ -191,15 +193,34 @@
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"])
{
priority = 1;
description = [self labelForKey: @"highest" inContext: context];
}
else if ([s hasPrefix: @"2"])
{
priority = 2;
description = [self labelForKey: @"high" inContext: context];
}
else if ([s hasPrefix: @"4"])
{
priority = 4;
description = [self labelForKey: @"low" inContext: context];
}
else if ([s hasPrefix: @"5"])
{
priority = 5;
description = [self labelForKey: @"lowest" inContext: context];
}
}
}
}
return result;
return [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithInt: priority], @"level",
description, @"name",
nil];
}
- (NSString *) messageSubject
@@ -623,11 +644,12 @@
- (NSDictionary *) getUIDsInFolder: (SOGoMailFolder *) folder
withHeaders: (BOOL) includeHeaders
{
NSMutableDictionary *data;
NSArray *uids, *threadedUids, *headers;
NSRange r;
NSMutableDictionary *data;
SOGoMailAccount *account;
id quota;
NSRange r;
int count;
data = [NSMutableDictionary dictionary];
@@ -645,10 +667,14 @@
if (includeHeaders)
{
// Also retrieve the first headers, up to 'headersPrefetchMaxSize'
count = [[uids flattenedArray] count];
if (count > headersPrefetchMaxSize) count = headersPrefetchMaxSize;
NSArray *a;
a = [uids flattenedArray];
count = [a count];
if (count > headersPrefetchMaxSize)
count = headersPrefetchMaxSize;
r = NSMakeRange(0, count);
headers = [self getHeadersForUIDs: [[uids flattenedArray] subarrayWithRange: r]
headers = [self getHeadersForUIDs: [a subarrayWithRange: r]
inFolder: folder];
[data setObject: headers forKey: @"headers"];
@@ -717,6 +743,8 @@
* @apiSuccess (Success 200) {String} headers.From.email Sender's email address
* @apiSuccess (Success 200) {Number} headers.isRead 1 if message is read
* @apiSuccess (Success 200) {String} headers.Priority Priority
* @apiSuccess (Success 200) {String} headers.Priority.level Priority number
* @apiSuccess (Success 200) {String} headers.Priority.name Priority description
* @apiSuccess (Success 200) {String} headers.RelativeDate Message date relative to now
* @apiSuccess (Success 200) {String} headers.Size Formatted message size
* @apiSuccess (Success 200) {String[]} headers.Flags Flags, such as "answered" and "seen"
@@ -745,7 +773,6 @@
noHeaders = [[[requestContent objectForKey: @"sortingAttributes"] objectForKey:@"noHeaders"] boolValue];
data = [self getUIDsInFolder: folder
withHeaders: !noHeaders];
[response appendContentString: [data jsonRepresentation]];
return response;
@@ -879,7 +906,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"];
+31 -9
View File
@@ -87,6 +87,11 @@
[super dealloc];
}
- (NSString *) modulePath
{
return @"Mail";
}
- (void) _setupContext
{
SOGoUser *activeUser;
@@ -118,6 +123,18 @@
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;
@@ -311,12 +328,17 @@
- (WOResponse *) getFoldersStateAction
{
NSString *expandedFolders;
id o;
NSArray *expandedFolders;
[self _setupContext];
expandedFolders = [moduleSettings objectForKey: @"ExpandedFolders"];
o = [moduleSettings objectForKey: @"ExpandedFolders"];
if ([o isKindOfClass: [NSString class]])
expandedFolders = [o componentsSeparatedByString: @","];
else
expandedFolders = o;
return [self responseWithStatus: 200 andString: expandedFolders];
return [self responseWithStatus: 200 andJSONRepresentation: expandedFolders];
}
- (NSString *) verticalDragHandleStyle
@@ -374,14 +396,14 @@
- (WOResponse *) saveFoldersStateAction
{
WORequest *request;
NSString *expandedFolders;
NSArray *expandedFolders;
[self _setupContext];
request = [context request];
expandedFolders = [request formValueForKey: @"expandedFolders"];
expandedFolders = [[request contentAsString] objectFromJSONString];
[moduleSettings setObject: expandedFolders
forKey: @"ExpandedFolders"];
forKey: @"ExpandedFolders"];
[us synchronize];
@@ -603,7 +625,7 @@
- (NSString *) columnsDisplayCount
{
return [NSString stringWithFormat: @"%d", [[self columnsDisplayOrder] count]];
return [NSString stringWithFormat: @"%d", (int)[[self columnsDisplayOrder] count]];
}
- (void) setCurrentColumn: (NSDictionary *) newCurrentColumn
@@ -709,8 +731,8 @@
for (k = 0; k < [pathComponents count]; k++)
{
component = [NSString stringWithFormat: @"folder%@", [pathComponents objectAtIndex: k]];
[path appendString: [component asCSSIdentifier]];
component = [[pathComponents objectAtIndex: k] asCSSIdentifier];
[path appendString: [NSString stringWithFormat: @"folder%@", component]];
if (k < [pathComponents count] - 1)
[path appendString: @"/"];
}
+2 -1
View File
@@ -57,6 +57,7 @@
#import <Mailer/SOGoMailFolder.h>
#import <MailPartViewers/UIxMailRenderingContext.h> // cyclic
#import <MailPartViewers/UIxMailSizeFormatter.h>
#import <MailPartViewers/UIxMailPartViewer.h>
#import "WOContext+UIxMailer.h"
#import "UIxMailFormatter.h"
@@ -229,7 +230,7 @@ static NSString *mailETag = nil;
- (id <WOActionResults>) defaultAction
{
id <WOActionResults> response;
WOResponse *response;
NSString *s;
NSMutableDictionary *data;
NSArray *addresses;
+9
View File
@@ -342,10 +342,19 @@
actionClass = "UIxMailMainFrame";
actionName = "unseenCount";
};
mailAccounts = {
protectedBy = "View";
actionClass = "UIxMailMainFrame";
actionName = "mailAccounts";
};
// viewerTemplate = {
// protectedBy = "View";
// pageName = "UIxMailViewTemplate";
// };
UIxMailPopupView = {
protectedBy = "View";
pageName = "UIxMailPopupView";
};
UIxMailEditor = {
protectedBy = "View";
pageName = "UIxMailEditor";
+4 -1
View File
@@ -30,6 +30,9 @@
#import <NGObjWeb/WORequest.h>
#import <NGObjWeb/WOResponse.h>
#import <Common/WODirectAction+SOGo.h>
#import <ActiveSync/SOGoActiveSyncDispatcher.h>
@interface SOGoMicrosoftActiveSyncActions : WODirectAction
@end
@@ -47,7 +50,7 @@
id dispatcher;
Class clazz;
request = [context request];
request = (WORequest *)[context request];
response = [self responseWithStatus: 200];
bundle = [NSBundle bundleForClass: NSClassFromString(@"ActiveSyncProduct")];
+16 -12
View File
@@ -193,7 +193,7 @@
timeZone: [currentStartDate timeZone]];
// Increment counters for quarters of first hour
hourKey = [NSString stringWithFormat: @"%u", [currentDate hourOfDay]];
hourKey = [NSString stringWithFormat: @"%u", (unsigned int)[currentDate hourOfDay]];
hourData = [dayData objectForKey: hourKey];
if (!hourData)
{
@@ -224,7 +224,7 @@
while ([currentDate compare: currentEndDate] == NSOrderedAscending &&
[currentEndDate timeIntervalSinceDate: currentDate] >= 3600) // 1 hour
{
hourKey = [NSString stringWithFormat: @"%u", [currentDate hourOfDay]];
hourKey = [NSString stringWithFormat: @"%u", (unsigned int)[currentDate hourOfDay]];
hourData = [dayData objectForKey: hourKey];
if (!hourData)
{
@@ -251,7 +251,7 @@
// Increment counters for quarters of last hour
if ([currentEndDate timeIntervalSinceDate: currentDate] > 0)
{
hourKey = [NSString stringWithFormat: @"%u", [currentDate hourOfDay]];
hourKey = [NSString stringWithFormat: @"%u", (unsigned int)[currentDate hourOfDay]];
hourData = [dayData objectForKey: hourKey];
if (!hourData)
{
@@ -636,7 +636,7 @@
* @apiExample {curl} Example usage:
* curl -i http://localhost/SOGo/so/sogo1/foldersSearch?type=contact
*
* @apiParam {String} type Either 'calendar' or 'contact'
* @apiParam {String} type Either 'calendar' or 'contact'. If nothing is specifed, its both.
*
* @apiSuccess (Success 200) {Object[]} folders List of matching folders
* @apiSuccess (Success 200) {String} folders.name Path of folder
@@ -648,27 +648,31 @@
- (id <WOActionResults>) foldersSearchAction
{
NSString *folderType;
NSArray *folders;
NSMutableArray *folders;
NSDictionary *message;
id <WOActionResults> result;
SOGoUserFolder *userFolder;
folderType = [self queryParameterForKey: @"type"];
folders = [NSMutableArray array];
userFolder = [self clientObject];
if ([folderType length])
{
userFolder = [self clientObject];
folders = [userFolder foldersOfType: folderType
forUID: [userFolder ownerInContext: context]];
result = [self _foldersResponseForResults: folders];
[folders addObjectsFromArray: [userFolder foldersOfType: folderType
forUID: [userFolder ownerInContext: context]]];
}
else
{
message = [NSDictionary dictionaryWithObject: [self labelForKey: @"Missing type parameter"]
forKey: @"error"];
result = [self responseWithStatus: 400 andJSONRepresentation: message];
[folders addObjectsFromArray: [userFolder foldersOfType: @"calendar"
forUID: [userFolder ownerInContext: context]]];
[folders addObjectsFromArray: [userFolder foldersOfType: @"contact"
forUID: [userFolder ownerInContext: context]]];
}
result = [self _foldersResponseForResults: folders];
return result;
}
@@ -203,7 +203,7 @@
/* Event+task categories */
"category_none" = "Nenhum";
"calendar_category_labels" = "Aniversário,Negócios,Ligações,Concorrência,Cliente,Favoritos,Acompanhamento,Presentes,Feriados,Idéias,Meeting,Problemas,Miscelânea,Pessoal,Projetos,Feriado público,Posição,Fornecedores,Viagem,Férias";
"calendar_category_labels" = "Celebração Anual,Aniversário,Negócios,Ligações,Clientes,Concorrência,Comprador,Favoritos,Acompanhamento,Presentes,Feriados,Idéias,Reunião,Problemas,Miscelânea,Pessoal,Projetos,Feriado,Posição,Fornecedores,Viagem,Férias";
/* Default module */
"Calendar" = "Calendário";
@@ -24,10 +24,10 @@
/* vacation (auto-reply) */
"Enable vacation auto reply" = "Enable vacation auto reply";
"Auto reply message" ="Auto reply message";
"Email addresses (separated by commas)" ="Email addresses (separated by commas)";
"Auto reply message" = "Auto reply message";
"Email addresses (separated by commas)" = "Email addresses (separated by commas)";
"Add default email addresses" = "Add default email addresses";
"Days between responses" ="Days between responses";
"Days between responses" = "Days between responses";
"Do not send responses to mailing lists" = "Do not send responses to mailing lists";
"Disable auto reply on" = "Disable auto reply on";
"Always send vacation message response" = "Always send vacation message response";
@@ -47,10 +47,10 @@
/* d & t */
"Current Time Zone" ="Current Time Zone";
"Short Date Format" ="Short Date Format";
"Long Date Format" ="Long Date Format";
"Time Format" ="Time Format";
"Current Time Zone" = "Current Time Zone";
"Short Date Format" = "Short Date Format";
"Long Date Format" = "Long Date Format";
"Time Format" = "Time Format";
"default" = "Default";
"Default Module" = "Default Module";
@@ -98,15 +98,15 @@
"timeFmt_4" = "";
/* calendar */
"Week begins on" ="Week begins on";
"Day start time" ="Day start time";
"Day end time" ="Day end time";
"Week begins on" = "Week begins on";
"Day start time" = "Day start time";
"Day end time" = "Day end time";
"Day start time must be prior to day end time." = "Day start time must be prior to day end time.";
"Show time as busy outside working hours" = "Show time as busy outside working hours";
"First week of year" ="First week of year";
"First week of year" = "First week of year";
"Enable reminders for Calendar items" = "Enable reminders for Calendar items";
"Play a sound when a reminder comes due" = "Play a sound when a reminder comes due";
"Default reminder" ="Default reminder";
"Default reminder" = "Default reminder";
"firstWeekOfYear_January1" = "Starts on january 1";
"firstWeekOfYear_First4DayWeek" = "First 4-day week";
@@ -117,7 +117,7 @@
"Contacts Names" = "Contacts Names";
/* Default Calendar */
"Default calendar" ="Default calendar";
"Default calendar" = "Default calendar";
"selectedCalendar" = "Selected calendar";
"personalCalendar" = "Personal calendar";
"firstCalendar" = "First enabled calendar";
@@ -200,8 +200,8 @@
"Change" = "Change";
/* Event+task classifications */
"Default events classification" ="Default events classification";
"Default tasks classification" ="Default tasks classification";
"Default events classification" = "Default events classification";
"Default tasks classification" = "Default tasks classification";
"PUBLIC_item" = "Public";
"CONFIDENTIAL_item" = "Confidential";
"PRIVATE_item" = "Private";
@@ -222,9 +222,11 @@
"Mail" = "Mail";
"Last" = "Last used";
"Default Module " = "Default Module";
"SOGo Version" ="SOGo Version";
"SOGo Version" = "SOGo Version";
"Language" ="Language";
/* Confirmation asked when changing the language */
"Save preferences and reload page now?" = "Save preferences and reload page now?";
"Language" = "Language";
"choose" = "Choose ...";
"Arabic" = "العربية";
"Basque" = "Euskara";
@@ -253,7 +255,7 @@
"Ukrainian" = "Українська";
"Welsh" = "Cymraeg";
"Refresh View" ="Refresh View";
"Refresh View" = "Refresh View";
"refreshview_manually" = "Manually";
"refreshview_every_minute" = "Every minute";
"refreshview_every_2_minutes" = "Every 2 minutes";
@@ -320,6 +322,9 @@
"matches regex" = "matches regex";
"does not match regex" = "does not match regex";
/* Placeholder for the value field of a condition */
"Value" = "Value";
"Seen" = "Seen";
"Deleted" = "Deleted";
"Answered" = "Answered";
@@ -357,3 +362,10 @@
"SSL" = "SSL";
"TLS" = "TLS";
/* Avatars */
"Alternate Avatar" = "Alternate Avatar";
"none" = "None";
"identicon" = "Ident Icon";
"monsterid" = "Monster";
"wavatar" = "Wavatar";
"retro" = "Retro";
+4
View File
@@ -32,6 +32,7 @@
#import <SOGo/SOGoUserDefaults.h>
#import <SOGo/SOGoUserSettings.h>
#import <SOGo/SOGoUserProfile.h>
#import <SOGo/WOResourceManager+SOGo.h>
#import <Mailer/SOGoMailLabel.h>
#import <SOGoUI/UIxComponent.h>
@@ -95,6 +96,9 @@ static SoProduct *preferencesProduct = nil;
if (![[defaults source] objectForKey: @"SOGoRefreshViewCheck"])
[[defaults source] setObject: [defaults refreshViewCheck] forKey: @"SOGoRefreshViewCheck"];
if (![[defaults source] objectForKey: @"SOGoAlternateAvatar"])
[[defaults source] setObject: [defaults alternateAvatar] forKey: @"SOGoAlternateAvatar"];
//
// Default Calendar preferences
//
+27 -6
View File
@@ -169,6 +169,11 @@ static NSArray *reminderValues = nil;
[super dealloc];
}
- (NSString *) modulePath
{
return @"Preferences";
}
// - (void) setHasChanged: (BOOL) newHasChanged
// {
// hasChanged = newHasChanged;
@@ -1375,6 +1380,18 @@ static NSArray *reminderValues = nil;
return [self labelForKey: item];
}
- (NSArray *) alternateAvatar
{
// See: https://en.gravatar.com/site/implement/images/
return [NSArray arrayWithObjects: @"none", @"identicon", @"monsterid", @"wavatar", @"retro", nil];
}
- (NSString *) itemAlternateAvatarText
{
return [self labelForKey: item];
}
// - (NSString *) userDefaultModule
// {
// NSString *userDefaultModule;
@@ -1466,15 +1483,15 @@ static NSArray *reminderValues = nil;
// if ([account updateFilters])
// // If Sieve is not enabled, the SOGoSieveManager will immediatly return a positive answer
// // See [SOGoSieveManager updateFiltersForAccount:withUsername:andPassword:]
// results = [self responseWithStatus: 200
// results = (id <WOActionResults>)[self responseWithStatus: 200
// andJSONRepresentation: [NSDictionary dictionaryWithObjectsAndKeys: [NSNumber numberWithBool:hasChanged], @"hasChanged", nil]];
// else
// results = [self responseWithStatus: 502
// results = (id <WOActionResults>)[self responseWithStatus: 502
// andJSONRepresentation: [NSDictionary dictionaryWithObjectsAndKeys: @"Connection error", @"textStatus", nil]];
// }
// else
// results = [self responseWithStatus: 503
// results = (id <WOActionResults>)[self responseWithStatus: 503
// andJSONRepresentation: [NSDictionary dictionaryWithObjectsAndKeys: @"Service temporarily unavailable", @"textStatus", nil]];
// }
// else
@@ -2086,6 +2103,10 @@ static NSArray *reminderValues = nil;
// We convert our object into a mutable one
v = [[v mutableCopy] autorelease];
if ([[v objectForKey: @"SOGoLoginModule"] isEqualToString: @"Last"])
[v setObject: [NSNumber numberWithBool: YES] forKey: @"SOGoRememberLastModule"];
else
[v setObject: [NSNumber numberWithBool: NO] forKey: @"SOGoRememberLastModule"];
// We remove short/long date formats if they are default ones
if ([[v objectForKey: @"SOGoShortDateFormat"] isEqualToString: @"default"])
@@ -2158,12 +2179,12 @@ static NSArray *reminderValues = nil;
if (![account updateFilters])
{
results = [self responseWithStatus: 502
results = (id <WOActionResults>) [self responseWithStatus: 502
andJSONRepresentation: [NSDictionary dictionaryWithObjectsAndKeys: @"Connection error", @"textStatus", nil]];
}
}
else
results = [self responseWithStatus: 503
results = (id <WOActionResults>) [self responseWithStatus: 503
andJSONRepresentation: [NSDictionary dictionaryWithObjectsAndKeys: @"Service temporarily unavailable", @"textStatus", nil]];
}
}
@@ -2175,7 +2196,7 @@ static NSArray *reminderValues = nil;
}
if (!results)
results = [self responseWithStatus: 200];
results = (id <WOActionResults>) [self responseWithStatus: 200];
return results;
}
+5 -5
View File
@@ -155,14 +155,14 @@
*/
[_buf appendFormat:@"%02i:%02i",
[_date hourOfDay],
[_date minuteOfHour]];
(int)[_date hourOfDay],
(int)[_date minuteOfHour]];
if (_refDate && ![_date isDateOnSameDay:_refDate]) {
[_buf appendFormat:@" (%02i-%02i",
[_date monthOfYear],
[_date dayOfMonth]];
(int)[_date monthOfYear],
(int)[_date dayOfMonth]];
if ([_date yearOfCommonEra] != [_refDate yearOfCommonEra])
[_buf appendFormat:@"-%04i", [_date yearOfCommonEra]];
[_buf appendFormat:@"-%04i", (int)[_date yearOfCommonEra]];
[_buf appendString:@")"];
}
}
+9 -30
View File
@@ -360,40 +360,19 @@ static SoProduct *commonProduct = nil;
- (NSString *) modulePath
{
SOGoObject *currentClient, *parent;
BOOL found;
NSString *hostLessURL;
Class objectClass, userFolderClass;
// , groupFolderClass
currentClient = [self clientObject];
if (currentClient
&& [currentClient isKindOfClass: [SOGoObject class]])
if ([[self parent] respondsToSelector: @selector(modulePath)])
{
// groupFolderClass = [SOGoCustomGroupFolder class];
userFolderClass = [SOGoUserFolder class];
NSString *baseURL;
objectClass = [currentClient class];
// found = (objectClass == groupFolderClass || objectClass == userFolderClass);
found = (objectClass == userFolderClass);
while (!found && currentClient)
{
parent = [currentClient container];
objectClass = [parent class];
if (// objectClass == groupFolderClass
// ||
objectClass == userFolderClass)
found = YES;
else
currentClient = parent;
}
baseURL = [[self clientObject] baseURLInContext: context];
if ([baseURL hasSuffix: [NSString stringWithFormat: @"%@/", [[self parent] modulePath]]])
return baseURL;
return [NSString stringWithFormat: @"%@%@", baseURL, [[self parent] modulePath]];
}
else
currentClient = [WOApplication application];
hostLessURL = [[currentClient baseURLInContext: context] hostlessURL];
return [hostLessURL substringToIndex: [hostLessURL length] - 1];
return @"SOGo";
}
- (NSString *) ownPath
@@ -446,6 +446,9 @@ validate_endbeforestart = "The end date that you entered occurs before the st
"Month View" = "Month View";
"Reload" = "Reload";
/* Number of selected components in events or tasks list */
"selected" = "selected";
"eventPartStatModificationError" = "Your participation status could not be modified.";
/* menu */
@@ -231,7 +231,7 @@
/* Searching */
"view_all" = "Todos los eventos";
"view_all" = "Todos";
"view_today" = "Hoy";
"view_next7" = "Próximos 7 días";
"view_next14" = "Próximos 14 días";
+13 -11
View File
@@ -38,6 +38,7 @@
#import <SOGo/NSCalendarDate+SOGo.h>
#import <SOGo/NSDictionary+Utilities.h>
#import <SOGo/NSString+Utilities.h>
#import <SOGo/SOGoUser.h>
#import <SOGo/SOGoUserDefaults.h>
#import <Appointments/iCalEvent+SOGo.h>
@@ -59,23 +60,25 @@
SoSecurityManager *sm;
iCalEvent *event;
NSCalendarDate *start, *newStart, *end, *newEnd;
NSDictionary *params;
NSTimeInterval newDuration;
SOGoUserDefaults *ud;
NSString *daysDelta, *startDelta, *durationDelta, *destionationCalendar;
NSNumber *daysDelta, *startDelta, *durationDelta;
NSString *destionationCalendar;
NSTimeZone *tz;
NSException *ex;
SOGoAppointmentFolder *targetCalendar, *sourceCalendar;
SOGoAppointmentFolders *folders;
rq = [context request];
params = [[rq contentAsString] objectFromJSONString];
daysDelta = [rq formValueForKey: @"days"];
startDelta = [rq formValueForKey: @"start"];
durationDelta = [rq formValueForKey: @"duration"];
destionationCalendar = [rq formValueForKey: @"destination"];
daysDelta = [params objectForKey: @"days"];
startDelta = [params objectForKey: @"start"];
durationDelta = [params objectForKey: @"duration"];
destionationCalendar = [params objectForKey: @"destination"];
if ([daysDelta length] > 0
|| [startDelta length] > 0 || [durationDelta length] > 0)
if (daysDelta || startDelta || durationDelta)
{
co = [self clientObject];
event = (iCalEvent *) [[self clientObject] occurence];
@@ -119,7 +122,7 @@
[event setLastModified: [NSCalendarDate calendarDate]];
ex = [co saveComponent: event];
// This condition will be executed only if the event is moved from a calendar to another. If destionationCalendar == 0; there is no calendar change
if (![destionationCalendar isEqualToString:@"0"])
if ([destionationCalendar length] > 0)
{
folders = [[self->context activeUser] calendarsFolderInContext: self->context];
sourceCalendar = [co container];
@@ -151,9 +154,8 @@
response = [self responseWith204];
}
else
response
= (WOResponse *) [NSException exceptionWithHTTPStatus: 400
reason: @"missing 'days', 'start' and/or 'duration' parameters"];
response = (WOResponse *) [NSException exceptionWithHTTPStatus: 400
reason: @"missing 'days', 'start' and/or 'duration' parameters"];
return response;
}
+22 -7
View File
@@ -595,12 +595,12 @@
* @apiSuccess (Success 200) {Boolean} alarm.attendees Alert attendees by email if true and action is email
* @apiSuccess (Success 200) {Boolean} alarm.organizer Alert organizer by email if true and action is email
*
* @apiSuccess {_} ... _From [iCalEvent+SOGo attributes]_
* @apiSuccess {_} ... _From [iCalEvent+SOGo attributesInContext:]_
*
* @apiSuccess (Success 200) {Number} isAllDay 1 if event is all-day
* @apiSuccess (Success 200) {Number} isTransparent 1 if the event is not opaque
*
* @apiSuccess {_} .... _From [iCalEntityObject+SOGo attributes]_
* @apiSuccess {_} .... _From [iCalEntityObject+SOGo attributesInContext:]_
*
* @apiSuccess (Success 200) {Number} sendAppointmentNotifications 1 if notifications must be sent
* @apiSuccess (Success 200) {String} component "vevent"
@@ -626,7 +626,7 @@
* @apiSuccess (Success 200) {String} [attendees.delegatedTo] User that the original request was delegated to
* @apiSuccess (Success 200) {String} [attendees.delegatedFrom] User the request was delegated from
*
* @apiSuccess {_} ..... _From [iCalRepeatableEntityObject+SOGo attributes]_
* @apiSuccess {_} ..... _From [iCalRepeatableEntityObject+SOGo attributesInContext:]_
*
* @apiSuccess (Success 200) {Object} [repeat] Recurrence rule definition
* @apiSuccess (Success 200) {String} repeat.frequency Either daily, (every weekday), weekly, (bi-weekly), monthly, or yearly
@@ -652,7 +652,8 @@
iCalEvent *event;
BOOL resetAlarm;
unsigned int snoozeAlarm;
NSInteger offset;
NSUInteger snoozeAlarm;
event = [self event];
co = [self clientObject];
@@ -662,12 +663,23 @@
timeZone = [ud timeZone];
eventStartDate = [event startDate];
eventEndDate = [event endDate];
if (!isAllDay)
if (isAllDay)
{
[eventStartDate setTimeZone: timeZone];
[eventEndDate setTimeZone: timeZone];
eventEndDate = [eventEndDate dateByAddingYears: 0 months: 0 days: -1];
// Convert the dates to the user's timezone
offset = [timeZone secondsFromGMTForDate: eventStartDate];
eventStartDate = [eventStartDate dateByAddingYears:0 months:0 days:0 hours:0 minutes:0
seconds:-offset];
offset = [timeZone secondsFromGMTForDate: eventEndDate];
eventEndDate = [eventEndDate dateByAddingYears:0 months:0 days:0 hours:0 minutes:0
seconds:-offset];
}
[eventStartDate setTimeZone: timeZone];
[eventEndDate setTimeZone: timeZone];
// resetAlarm=yes is set only when we are about to show the alarm popup in the Web
// interface of SOGo. See generic.js for details. snoozeAlarm=X is called when the
// user clicks on "Snooze for" X minutes, when the popup is being displayed.
@@ -704,8 +716,11 @@
data = [NSMutableDictionary dictionaryWithObjectsAndKeys:
[componentCalendar nameInContainer], @"pid",
[componentCalendar displayName], @"calendar",
[NSNumber numberWithBool: isAllDay], @"isAllDay",
[NSNumber numberWithBool: [self isReadOnly]], @"isReadOnly",
[NSNumber numberWithBool: [self userHasRSVP]], @"userHasRSVP",
[eventStartDate iso8601DateString], @"startDate",
[eventEndDate iso8601DateString], @"endDate",
[dateFormatter formattedDate: eventStartDate], @"localizedStartDate",
[dateFormatter formattedDate: eventEndDate], @"localizedEndDate",
[self alarm], @"alarm",
+2 -2
View File
@@ -117,7 +117,7 @@
date = [self startDate];
return [NSString stringWithFormat: @"%.2d", [date monthOfYear]];
return [NSString stringWithFormat: @"%.2d", (int)[date monthOfYear]];
}
- (NSString *) headerMonthString
@@ -136,7 +136,7 @@
date = [self startDate];
return [NSString stringWithFormat: @"%d", [date yearOfCommonEra]];
return [NSString stringWithFormat: @"%d", (int)[date yearOfCommonEra]];
}
- (NSString *) localizedDayOfWeekName
+3 -2
View File
@@ -39,7 +39,8 @@
NSArray *weekDays;
NSString *currentView, *timeFormat, *currentTableHour;
NSCalendarDate *startDate, *currentTableDay;
NSMutableArray *daysToDisplay, *calendarsToDisplay, *currentCalendar, *hoursToDisplay;
NSMutableArray *daysToDisplay, *calendarsToDisplay, *hoursToDisplay;
NSMutableDictionary *currentCalendar;
unsigned int numberOfDays;
}
@@ -55,7 +56,7 @@
- (NSArray *) calendarsToDisplay;
- (void) setCurrentTableDay: (NSCalendarDate *) aTableDay;
- (NSCalendarDate *) currentTableDay;
- (NSMutableArray *) currentCalendar;
- (NSMutableDictionary *) currentCalendar;
@end
+67 -26
View File
@@ -37,6 +37,9 @@
#import <SOGo/SOGoUserDefaults.h>
#import <SOGo/WOResourceManager+SOGo.h>
#import <SoObjects/Appointments/SOGoAppointmentFolder.h>
#import <SoObjects/Appointments/SOGoAppointmentFolders.h>
#import "UIxCalDayTable.h"
@class SOGoAppointment;
@@ -184,14 +187,13 @@
{
if (!calendarsToDisplay)
{
int max=0, i;
NSArray *folders;
SOGoAppointmentFolders *co;
SOGoAppointmentFolder *folder;
NSMutableDictionary *calendar;
unsigned int count, foldersCount;
NSString *folderName, *fDisplayName;
NSNumber *isActive;
BOOL isActive;
co = [self clientObject];
folders = [co subFolders];
@@ -200,8 +202,8 @@
for (count = 0; count < foldersCount; count++)
{
folder = [folders objectAtIndex: count];
isActive = [NSNumber numberWithBool: [folder isActive]];
if ([isActive intValue] != 0) {
isActive = [folder isActive];
if (isActive != NO) {
calendar = [NSMutableDictionary dictionary];
folderName = [folder nameInContainer];
fDisplayName = [folder displayName];
@@ -214,7 +216,7 @@
[calendar setObject: fDisplayName forKey: @"displayName"];
[calendar setObject: folderName forKey: @"folder"];
[calendar setObject: [folder calendarColor] forKey: @"color"];
[calendar setObject: isActive forKey: @"active"];
[calendar setObject: [NSNumber numberWithBool:isActive] forKey: @"active"];
[calendar setObject: [folder ownerInContext: context]
forKey: @"owner"];
[calendarsToDisplay addObject: calendar];
@@ -235,12 +237,12 @@
return currentTableDay;
}
- (void) setCurrentCalendar: (NSMutableArray *) aCalendar
- (void) setCurrentCalendar: (NSMutableDictionary *) aCalendar
{
ASSIGN(currentCalendar, aCalendar);
}
- (NSMutableArray *) currentCalendar
- (NSMutableDictionary *) currentCalendar
{
return currentCalendar;
}
@@ -282,9 +284,9 @@
return [daysToDisplay indexOfObject: currentTableDay];
}
- (NSString *) currentAppointmentHour
- (NSNumber *) currentAppointmentHour
{
return [NSString stringWithFormat: @"%.2d00", [currentTableHour intValue]];
return [NSNumber numberWithInt: [currentTableHour intValue]];
}
- (NSString *) labelForDay
@@ -292,6 +294,39 @@
return [weekDays objectAtIndex: [currentTableDay dayOfWeek]];
}
- (NSString *) labelForMonth
{
NSCalendarDate *nextDay;
NSString *calendarFormat;
BOOL isLastOrFirstDay;
isLastOrFirstDay = NO;
calendarFormat = @"%b";
if ([currentView hasSuffix: @"dayview"])
{
isLastOrFirstDay = YES;
calendarFormat = @"%B";
}
else
{
if ([currentTableDay dayOfMonth] == 1)
{
isLastOrFirstDay = YES;
}
else if ([currentTableDay dayOfMonth] > 27)
{
nextDay = [currentTableDay dateByAddingYears: 0
months: 0
days: 1];
if ([nextDay dayOfMonth] == 1)
isLastOrFirstDay = YES;
}
}
return isLastOrFirstDay? [currentTableDay descriptionWithCalendarFormat: calendarFormat locale: locale] : nil;
}
- (NSString *) labelForDate
{
return [dateFormatter shortFormattedDate: currentTableDay];
@@ -397,18 +432,23 @@
numberOfDays];
}
- (NSString *) daysViewClasses
{
NSString *daysView;
// - (NSString *) daysViewClasses
// {
// NSString *daysView;
if ([currentView isEqualToString:@"multicolumndayview"])
daysView = @"daysView daysViewForMultipleDays";
// if ([currentView isEqualToString:@"multicolumndayview"])
// daysView = @"daysView daysViewForMultipleDays";
else
daysView = [NSString stringWithFormat: @"daysView daysViewFor%dDays", numberOfDays];
// else
// daysView = [NSString stringWithFormat: @"daysView daysViewFor%dDays", numberOfDays];
return daysView;
}
// return daysView;
//}
// - (NSString *) daysViewHeaderClasses
// {
// return [NSString stringWithFormat: @"%@ daysHeader", [self daysViewClasses]];
// }
- (NSString *) dayClasses
{
@@ -416,22 +456,18 @@
unsigned int currentDayNbr, realDayOfWeek;
classes = [NSMutableString string];
if ([currentView isEqualToString:@"multicolumndayview"])
[classes appendFormat:@"day dayColumn"];
else {
currentDayNbr = [daysToDisplay indexOfObject: currentTableDay];
realDayOfWeek = [currentTableDay dayOfWeek];
currentDayNbr = [daysToDisplay indexOfObject: currentTableDay];
realDayOfWeek = [currentTableDay dayOfWeek];
[classes appendFormat: @"day day%d", currentDayNbr];
[classes appendFormat: @"day day%d", currentDayNbr];
if (numberOfDays > 1)
if (numberOfDays > 1)
{
if (realDayOfWeek == 0 || realDayOfWeek == 6)
[classes appendString: @" weekEndDay"];
if ([currentTableDay isToday])
[classes appendString: @" dayOfToday"];
}
}
return classes;
}
@@ -468,4 +504,9 @@
return NO;
}
- (BOOL) isWeekView
{
return [currentView isEqualToString:@"weekview"];
}
@end
+1 -1
View File
@@ -164,7 +164,7 @@
date = [self selectedDate];
hmString = [NSString stringWithFormat:@"%.2d%.2d",
[date hourOfDay], [date minuteOfHour]];
(int)[date hourOfDay], (int)[date minuteOfHour]];
qp = [[self queryParameters] mutableCopy];
[self setSelectedDateQueryParameter:date inDictionary:qp];
[qp setObject: hmString forKey:@"hm"];
+8 -12
View File
@@ -72,18 +72,14 @@
rc = [NSMutableDictionary dictionary];
request = [context request];
folder = [self clientObject];
data = [request formValueForKey: @"calendarFile"];
if ([data respondsToSelector: @selector(isEqualToString:)])
fileContent = (NSString *) data;
else
{
fileContent = [[NSString alloc] initWithData: (NSData *) data
encoding: NSUTF8StringEncoding];
if (fileContent == nil)
fileContent = [[NSString alloc] initWithData: (NSData *) data
encoding: NSISOLatin1StringEncoding];
[fileContent autorelease];
}
data = [[[[[request httpRequest] body] parts] lastObject] body];
fileContent = [[NSString alloc] initWithData: (NSData *) data
encoding: NSUTF8StringEncoding];
if (fileContent == nil)
fileContent = [[NSString alloc] initWithData: (NSData *) data
encoding: NSISOLatin1StringEncoding];
[fileContent autorelease];
if (fileContent && [fileContent length]
&& [fileContent hasPrefix: @"BEGIN:"])
+55 -33
View File
@@ -328,16 +328,24 @@ static NSArray *tasksFields = nil;
iCalPersonPartStat stat;
NSUInteger count, max;
if ([[theRecord objectForKey: @"c_partmails"] length] > 0 &&
[[theRecord objectForKey: @"c_partstates"] length] > 0)
states = nil;
if ([[theRecord objectForKey: @"c_partmails"] length] > 0)
{
mails = [[theRecord objectForKey: @"c_partmails"] componentsSeparatedByString: @"\n"];
states = [[theRecord objectForKey: @"c_partstates"] componentsSeparatedByString: @"\n"];
// We add some robustness here, in case the quick table had c_partmails defined but
// no corresponding c_partstates entries. This can happen if folks toy around the database
// or if Funambol was used in the past, with a broken connector.
if ([[theRecord objectForKey: @"c_partstates"] length] > 0)
states = [[theRecord objectForKey: @"c_partstates"] componentsSeparatedByString: @"\n"];
max = [mails count];
statesDescription = [NSMutableArray arrayWithCapacity: max];
for (count = 0; count < max; count++)
{
stat = [[states objectAtIndex: count] intValue];
stat = (states ? [[states objectAtIndex: count] intValue] : 0);
[statesDescription addObject: [[iCalPerson descriptionForParticipationStatus: stat] lowercaseString]];
}
@@ -356,10 +364,10 @@ static NSArray *tasksFields = nil;
NSMutableDictionary *newInfo;
NSMutableArray *infos, *quickInfos, *allInfos, *quickInfosName;
NSNull *marker;
NSString *owner, *role, *calendarName, *iCalString, *recurrenceTime;
NSString *owner, *role, *calendarName, *iCalString, *recurrenceTime, *categories;
NSRange match;
iCalCalendar *calendar;
iCalObject *master;
iCalEntityObject *master;
SOGoAppointmentFolder *currentFolder;
SOGoAppointmentFolders *clientObject;
SOGoUser *ownerUser;
@@ -392,7 +400,7 @@ static NSArray *tasksFields = nil;
else if ([criteria isEqualToString:@"entireContent"])
{
// First search : Through the quick table inside the location, category and title columns
quickInfos = [currentFolder fetchCoreInfosFrom: startDate
quickInfos = (NSMutableArray *)[currentFolder fetchCoreInfosFrom: startDate
to: endDate
title: value
component: component
@@ -408,14 +416,14 @@ static NSArray *tasksFields = nil;
}
// Second research : Every objects except for those already in the quickInfos array
allInfos = [currentFolder fetchCoreInfosFrom: startDate
allInfos = (NSMutableArray *)[currentFolder fetchCoreInfosFrom: startDate
to: endDate
title: nil
component: component];
if (quickInfosFlag == YES)
{
for (i = ([allInfos count] - 1); i >= 0 ; i--) {
if([quickInfosName containsObject:[[allInfos objectAtIndex:i] objectForKey:@"c_name"]])
if ([quickInfosName containsObject:[[allInfos objectAtIndex:i] objectForKey:@"c_name"]])
[allInfos removeObjectAtIndex:i];
}
}
@@ -425,7 +433,7 @@ static NSArray *tasksFields = nil;
{
iCalString = [[allInfos objectAtIndex:i] objectForKey:@"c_content"];
calendar = [iCalCalendar parseSingleFromSource: iCalString];
master = [calendar firstChildWithTag:component];
master = (iCalEntityObject *)[calendar firstChildWithTag:component];
if (master) {
if ([[master comment] length] > 0)
{
@@ -463,10 +471,10 @@ static NSArray *tasksFields = nil;
role = [currentFolder roleForComponentsWithAccessClass: [[newInfo objectForKey: @"c_classification"] intValue]
forUser : userLogin];
if ([role isEqualToString: @"ComponentViewer"])
[newInfo setObject: [NSNumber numberWithInt: 1] forKey: @"viewable"];
else
if ([role isEqualToString: @"ComponentDAndTViewer"])
[newInfo setObject: [NSNumber numberWithInt: 0] forKey: @"viewable"];
else
[newInfo setObject: [NSNumber numberWithInt: 1] forKey: @"viewable"];
}
}
@@ -514,6 +522,11 @@ static NSArray *tasksFields = nil;
[newInfo setObject: calendarName
forKey: @"calendarName"];
// Split comma-delimited categories
categories = [newInfo objectForKey: @"c_category"];
if ([categories length])
[newInfo setObject: [categories componentsSeparatedByString: @","] forKey: @"c_category"];
// Fix empty title
if (![[newInfo objectForKey: @"c_title"] length])
[self _fixComponentTitle: newInfo withType: component];
@@ -892,10 +905,10 @@ static inline iCalPersonPartStat _userStateInEvent (NSArray *event)
states = [event objectAtIndex: eventPartStatesIndex];
count = 0;
max = [participants count];
user = [SOGoUser userWithLogin: [event objectAtIndex: eventOwnerIndex]
roles: nil];
while (state == iCalPersonPartStatOther && count < max)
{
user = [SOGoUser userWithLogin: [event objectAtIndex: eventOwnerIndex]
roles: nil];
if ([user hasEmail: [participants objectAtIndex: count]])
state = [[states objectAtIndex: count] intValue];
else
@@ -933,7 +946,7 @@ static inline iCalPersonPartStat _userStateInEvent (NSArray *event)
eventStart = eventEnd;
eventEnd = swap;
[self warnWithFormat: @"event '%@' has end < start: %d < %d",
[event objectAtIndex: eventNameIndex], eventEnd, eventStart];
[event objectAtIndex: eventNameIndex], eventEnd, eventStart];
}
startSecs = (unsigned int) [startDate timeIntervalSince1970];
@@ -986,21 +999,21 @@ static inline iCalPersonPartStat _userStateInEvent (NSArray *event)
currentDay = [blocks objectAtIndex: offset];
}
computedEventEnd = eventEnd;
computedEventEnd = eventEnd;
// We add 5 mins to the end date of an event if the end date
// is equal or smaller than the event's start date.
if (eventEnd <= currentStart)
// We add 5 mins to the end date of an event if the end date
// is equal or smaller than the event's start date.
if (eventEnd <= currentStart)
computedEventEnd = currentStart + (5*60);
eventBlock = [self _eventBlockWithStart: currentStart
eventBlock = [self _eventBlockWithStart: currentStart
end: computedEventEnd
number: number
onDay: currentDayStart
recurrenceTime: recurrenceTime
userState: userState];
[currentDay addObject: eventBlock];
}
[currentDay addObject: eventBlock];
}
}
}
}
@@ -1217,7 +1230,7 @@ _computeBlocksPosition (NSArray *blocks)
SOGoAppointmentFolder *folder;
NSMutableArray *selectedCalendars;
NSArray *folders;
NSString *fUID;
NSString *fUID, *fName;
NSNumber *isActive;
unsigned int count, foldersCount;
@@ -1231,7 +1244,11 @@ _computeBlocksPosition (NSArray *blocks)
isActive = [NSNumber numberWithBool: [folder isActive]];
if ([isActive intValue] != 0) {
fUID = [folder nameInContainer];
[selectedCalendars addObject: fUID];
fName = [folder displayName];
[selectedCalendars addObject: [NSDictionary dictionaryWithObjectsAndKeys:
fUID, @"id",
fName, @"name",
nil]];
}
}
return selectedCalendars;
@@ -1289,9 +1306,10 @@ _computeBlocksPosition (NSArray *blocks)
{
int count, max;
NSArray *events, *event, *calendars;
NSDictionary *eventsBlocks;
NSMutableArray *allDayBlocks, *blocks, *currentDay, *eventsByCalendars, *eventsForCalendar;
NSDictionary *eventsBlocks, *calendar;
NSMutableArray *allDayBlocks, *blocks, *currentDay, *eventsForCalendar, *eventsByCalendars;
NSNumber *eventNbr;
NSString *calendarName, *calendarId;
BOOL isAllDay;
int i, j;
@@ -1301,20 +1319,25 @@ _computeBlocksPosition (NSArray *blocks)
if ([currentView isEqualToString: @"multicolumndayview"])
{
calendars = [self _selectedCalendars];
calendars = (NSMutableArray *)[self _selectedCalendars];
eventsByCalendars = [NSMutableArray arrayWithCapacity:[calendars count]];
for (i = 0; i < [calendars count]; i++) // For each calendar
{
calendar = [calendars objectAtIndex:i];
calendarName = [calendar objectForKey: @"name"];
calendarId = [calendar objectForKey: @"id"];
eventsForCalendar = [NSMutableArray array];
[self _prepareEventBlocks: &blocks withAllDays: &allDayBlocks];
for (j = 0; j < [events count]; j++) {
if ([[[events objectAtIndex:j] objectAtIndex:eventFolderIndex] isEqualToString:[calendars objectAtIndex:i]]) {
if ([[[events objectAtIndex:j] objectAtIndex:eventFolderIndex] isEqualToString: calendarId]) {
// Event is in current calendar
[eventsForCalendar addObject: [events objectAtIndex:j]];
}
}
eventsBlocks = [NSDictionary dictionaryWithObjectsAndKeys:
eventsFields, @"eventsFields",
calendarId , @"id",
calendarName, @"calendarName",
eventsFields, @"eventsFields",
eventsForCalendar, @"events",
allDayBlocks, @"allDayBlocks",
blocks, @"blocks", nil];
@@ -1336,8 +1359,7 @@ _computeBlocksPosition (NSArray *blocks)
[currentDay sortUsingSelector: @selector (compareEventByStart:)];
[self _addBlocksWidth: currentDay];
}
[eventsByCalendars insertObject:eventsBlocks atIndex:i];
[eventsByCalendars addObject: eventsBlocks];
}
return [self _responseWithData: eventsByCalendars];
}
@@ -1373,7 +1395,7 @@ _computeBlocksPosition (NSArray *blocks)
[currentDay sortUsingSelector: @selector (compareEventByStart:)];
[self _addBlocksWidth: currentDay];
}
return [self _responseWithData: eventsBlocks];
return [self _responseWithData: [NSArray arrayWithObject: eventsBlocks]];
}
}
+5
View File
@@ -46,6 +46,11 @@
@implementation UIxCalMainView
- (NSString *) modulePath
{
return @"Calendar";
}
- (void) checkDefaultModulePreference
{
SOGoUserDefaults *ud;
+1 -4
View File
@@ -1,8 +1,6 @@
/* UIxCalMonthView.h - this file is part of SOGo
*
* Copyright (C) 2006-2009 Inverse inc.
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
* 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
@@ -69,7 +67,6 @@
- (void) setCurrentTableDay: (NSCalendarDate *) newCurrentTableDay;
- (NSCalendarDate *) currentTableDay;
- (NSString *) labelForCurrentDayCell;
@end
+6 -34
View File
@@ -1,8 +1,6 @@
/* UIxCalMonthView.m - this file is part of SOGo
*
* Copyright (C) 2006, 2007 Inverse inc.
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
* 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
@@ -235,27 +233,6 @@
return currentWeek;
}
- (NSString *) labelForCurrentDayCell
{
NSCalendarDate *lastDayOfMonth;
NSString *label, *monthOfYear;
int dayOfMonth;
dayOfMonth = [currentTableDay dayOfMonth];
lastDayOfMonth = [currentTableDay lastDayOfMonth];
if (dayOfMonth == 1
|| [currentTableDay isDateOnSameDay: lastDayOfMonth])
{
monthOfYear
= [monthNames objectAtIndex: [currentTableDay monthOfYear]];
label = [NSString stringWithFormat: @"%d %@", dayOfMonth, monthOfYear];
}
else
label = [NSString stringWithFormat: @"%d", dayOfMonth];
return label;
}
- (NSString *) headerDayCellClasses
{
unsigned int dayOfWeek;
@@ -265,24 +242,19 @@
return [NSString stringWithFormat: @"headerDay day%d", dayOfWeek];
}
- (NSString *) dayHeaderNumber
- (NSString *) dayHeaderMonth
{
NSString *nameOfMonth, *dayHeaderNumber;
NSString *nameOfMonth = nil;
unsigned int dayOfMonth;
dayOfMonth = [currentTableDay dayOfMonth];
if (dayOfMonth == 1
|| [currentTableDay isDateOnSameDay: [currentTableDay lastDayOfMonth]])
{
nameOfMonth
= [self localizedNameForMonthOfYear: [currentTableDay monthOfYear]];
dayHeaderNumber = [NSString stringWithFormat: @"%d %@", dayOfMonth,
nameOfMonth];
nameOfMonth = [self localizedNameForMonthOfYear: [currentTableDay monthOfYear]];
}
else
dayHeaderNumber = [NSString stringWithFormat: @"%d", dayOfMonth];
return dayHeaderNumber;
return nameOfMonth;
}
- (NSString *) dayCellClasses
@@ -299,7 +271,7 @@
[classes appendFormat: @"day weekOf%d week%dof%d day%d",
numberOfWeeks,
[weeksToDisplay indexOfObject: currentWeek],
(int)[weeksToDisplay indexOfObject: currentWeek],
numberOfWeeks, dayOfWeek];
if (realDayOfWeek == 0 || realDayOfWeek == 6)
[classes appendString: @" weekEndDay"];
+2 -1
View File
@@ -49,6 +49,7 @@ static NSArray *layoutItems = nil;
- (void) dealloc
{
[item release];
[super dealloc];
}
- (void) setItem: (NSString *) newItem
@@ -68,7 +69,7 @@ static NSArray *layoutItems = nil;
- (NSString *) itemPrintLayoutText
{
return [self labelForKey: [NSString stringWithFormat: item]];
return [self labelForKey: [NSString stringWithFormat: @"%@", item]];
}
//
+5
View File
@@ -68,6 +68,7 @@
* @apiParam {Number} includeInFreeBusy 1 if calendar must be include in freebusy
* @apiParam {Number} showCalendarAlarms 1 if alarms must be enabled
* @apiParam {Number} showCalendarTasks 1 if tasks must be enabled
* @apiParam {Number} synchronize 1 if we enable EAS synchronization for this calendar
* @apiParam {Number} reloadOnLogin 1 if calendar is a Web calendar that must be reload when user logins
* @apiParam {Object} [notifications] Notification (if active user is the calendar's owner)
* @apiParam {Number} notifications.notifyOnPersonalModifications 1 if a mail is sent for each modification made by the owner
@@ -108,6 +109,10 @@
if ([o isKindOfClass: [NSNumber class]])
[calendar setShowCalendarTasks: [o boolValue]];
o = [params objectForKey: @"synchronize"];
if ([o isKindOfClass: [NSNumber class]])
[calendar setSynchronize: [o boolValue]];
values = [params objectForKey: @"notifications"];
if ([values isKindOfClass: [NSDictionary class]])
{
+11 -1
View File
@@ -99,7 +99,7 @@ _intValueFromHex (NSString *hexString)
NSNumber *isActive, *fActiveTasks;
SOGoAppointmentFolders *co;
SOGoAppointmentFolder *folder;
BOOL reloadOnLogin;
BOOL reloadOnLogin, synchronize;
if (!calendars)
{
@@ -133,6 +133,16 @@ _intValueFromHex (NSString *hexString)
[calendar setObject: [NSNumber numberWithBool: [folder showCalendarAlarms]] forKey: @"showCalendarAlarms"];
[calendar setObject: [NSNumber numberWithBool: [folder showCalendarTasks]] forKey: @"showCalendarTasks"];
if ([folder isKindOfClass: [SOGoWebAppointmentFolder class]])
synchronize = NO;
else
synchronize = [folder synchronize];
if ([[folder nameInContainer] isEqualToString: @"personal"])
synchronize = YES;
[calendar setObject: [NSNumber numberWithBool: synchronize] forKey: @"synchronize"];
if ([folder isWebCalendar])
{
urls = [NSMutableDictionary dictionaryWithObject: [folder folderPropertyValueInCategory: @"WebCalendars"]
+1 -1
View File
@@ -896,7 +896,7 @@ static NSArray *reminderValues = nil;
content = [NSMutableString string];
response = [context response];
[content appendFormat: [[self clientObject] contentAsString]];
[content appendFormat: @"%@", [[self clientObject] contentAsString]];
[response setHeader: @"text/plain; charset=utf-8"
forKey: @"content-type"];
[response appendContentString: content];
+1 -1
View File
@@ -158,7 +158,7 @@
[shortWeekDaysList retain];
}
id = [NSString stringWithFormat: @"weekDay%i", [shortWeekDaysList indexOfObject: item]];
id = [NSString stringWithFormat: @"weekDay%i", (int)[shortWeekDaysList indexOfObject: item]];
return id;
}
+4
View File
@@ -182,6 +182,10 @@
actionClass = "UIxCalFolderActions";
actionName = "import";
};
UIxCalUserRightsEditor = {
protectedBy = "ReadAcls";
pageName = "UIxCalUserRightsEditor";
};
userRights = {
protectedBy = "ReadAcls";
pageName = "UIxCalUserRightsEditor";
@@ -1,40 +1,133 @@
<?xml version="1.0" standalone="yes"?>
<!DOCTYPE var:component>
<var:component xmlns="http://www.w3.org/1999/xhtml"
xmlns:var="http://www.skyrix.com/od/binding"
xmlns:const="http://www.skyrix.com/od/constant"
xmlns:rsrc="OGo:url"
xmlns:label="OGo:label"
className="UIxPageFrame"
title="title"
const:toolbar="UIxAdministration.toolbar"
const:jsFiles="dtree.js">
xmlns:var="http://www.skyrix.com/od/binding"
xmlns:const="http://www.skyrix.com/od/constant"
xmlns:rsrc="OGo:url"
xmlns:label="OGo:label"
className="UIxPageFrame"
title="title"
const:jsFiles="Common.js, Administration.js,
Administration.services.js, Preferences.services.js,
Contacts.services.js, Scheduler.services.js">
<div id="helpDialog" style="display: none" class="dialog left">
<div>
<h3><!-- module title --></h3>
<div><!-- module description --></div>
<a href="#" class="button" id="helpDialogClose"><span><var:string label:value="Close"/></span></a>
<main class="view layout-fill" ui-view="administration" layout="row" ng-controller="navController">
<!-- administration -->
</main>
<script type="text/ng-template" id="administration.html">
<md-sidenav id="left-sidenav" class="md-sidenav-left md-whiteframe-z1" md-component-id="left" md-is-locked-open="$mdMedia('gt-md')" layout="column">
<var:component className="UIxSidenavToolbarTemplate" />
<md-content md-scroll-y="md-scroll-y" class="md-flex md-hue-2">
<md-list>
<md-list-item ng-click="app.go('rights')"
ui-sref="administration.rights"
ui-sref-active="md-default-theme md-background md-bg md-hue-1">
<md-icon>security</md-icon>
<p class="sg-item-name"><var:string label:value="Rights"/></p>
</md-list-item>
</md-list>
</md-content>
</md-sidenav>
<section layout="column" class="sg-app-content layout-fill" ui-view="module"><!-- admin module --></section>
</script>
<!--
RIGHTS ADMINISTRATION PANEL
-->
<script type="text/ng-template" id="rights.html">
<!-- TOP RIGHT TOOLBAR -->
<md-toolbar layout="row" layout-align="space-between center" class="toolbar-main">
<var:component className="UIxTopnavToolbarTemplate" />
</md-toolbar>
<div layout="row" class="md-flex">
<div class="view-list" layout="column">
<md-toolbar>
<!-- search toolbar -->
<div class="md-toolbar-tools sg-toolbar-secondary"
sg-search="app.filter(searchText)">
<md-icon>search</md-icon>
<md-input-container md-no-float="md-no-float">
<input name="folderSearch" type="search" ng-minlength="3"
label:placeholder="Search Users"/>
</md-input-container>
</div>
</md-toolbar>
<md-content id="usersList" layout="column" class="md-flex">
<md-subheader ng-show="app.service.$query">
<span ng-switch="app.users.length">
<span ng-switch-when="0"><var:string label:value="No matching user"/></span>
<span ng-switch-default="true">{{app.users.length}} <var:string label:value="users found"/></span>
</span>
</md-subheader>
<md-subheader ng-hide="app.service.$query">
<var:string label:value="Start a search to edit the rights"/>
</md-subheader>
<md-list class="sg-section-list">
<div ng-repeat="user in app.users">
<md-list-item ng-class="{ 'sg-collapsed': user.uid != app.selectedUser.uid,
'sg-expanded': user.uid == app.selectedUser.uid }"
ng-click="app.selectUser($index)">
<sg-avatar-image class="md-avatar"
ng-if="::user.isGroup === 0"
sg-email="::user.c_email"
size="40">
<!-- contact avatar -->
</sg-avatar-image>
<div class="sg-list-avatar"
ng-show="::user.isGroup">
<!-- list avatar -->
</div>
<div class="sg-tile-content">
<div class="sg-md-subhead">
<div>{{::user.cn}}</div>
</div>
<div class="sg-md-body">
<div>{{::user.c_email}}</div>
</div>
</div>
<md-button class="md-icon-button"><md-icon ng-class="{'md-rotate-180': user.uid == app.selectedUser.uid}">expand_more</md-icon></md-button>
</md-list-item>
<div ng-show="user == app.selectedUser">
<!-- folders list -->
<md-list-item ng-show="user.$$folders.length == 0">
<md-icon>warning</md-icon>
<var:string label:value="No resource"/>
</md-list-item>
<md-list-item class="sg-folder" ng-repeat="folder in user.$$folders">
<md-button class=""
aria-label="{{::folder.displayName}}" title="{{::folder.displayName}}"
ng-click="app.selectFolder(folder)">
<md-icon ng-class="{ 'icon-contacts': folder.type == 'Contact',
'icon-event': folder.type == 'Appointment' }"><!--icon--></md-icon>
{{::folder.displayName}}
</md-button>
</md-list-item>
<md-divider><!-- divider --></md-divider>
</div>
</div>
</md-list>
</md-content>
</div>
<div id="detailView" class="view-detail" layout="column" layout-align="start center"
ng-class="{ 'sg-close': !app.selectedUser.selectedFolder }"
ui-view="acl">
<md-toolbar class="md-whiteframe-z1 hide-sm"><!-- empty toolbar --></md-toolbar>
<md-content class="hide-sm md-flex layout-fill md-hue-1"
layout="column" layout-align="center center">
<div class="md-default-theme md-background md-fg md-hue-3 sg-md-title">
<var:string label:value="No resource selected"/>
</div>
</md-content>
</div>
</div>
</div>
</script>
<div id="leftPanel">
<div class="titlediv"><var:string label:value="Modules" /></div>
<div id="administrationModules">
<ul>
<li id="ACLs" class="_selected"><var:string label:value="ACLs"/></li>
</ul>
</div>
</div>
<div class="dragHandle" id="verticalDragHandle"><!-- space --></div>
<div id="rightPanel">
<span><h1 id="moduleTitle"><var:string label:value="ACLs_title"/></h1>
<div id="moduleDescription" style="display: none"><var:string label:value="ACLs_description" const:escapeHTML="NO"/></div></span>
<var:component className="UIxAdministrationFilterPanel" qualifier="qualifier" />
<div id="administrationContent"><!-- space --></div>
</div>
<var:string value="errorAlertJavaScript" const:escapeHTML="NO" />
</var:component>
@@ -0,0 +1,124 @@
<?xml version="1.0" standalone="yes"?>
<!DOCTYPE container>
<container
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"
>
<div layout="column" class="layout-fill">
<md-toolbar class="hide show-sm">
<div class="md-toolbar-tools">
<md-button class="sg-icon-button"
label:aria-label="Close"
ng-click="acl.close()">
<md-icon>close</md-icon>
</md-button>
<div class="md-flex"><!-- spacer --></div>
<md-button class="md-icon-button"
ng-click="acl.save()">
<md-icon>save</md-icon>
</md-button>
</div>
</md-toolbar>
<md-toolbar class="md-tall">
<div layout="row">
<sg-avatar-image class="md-tile-left"
ng-show="acl.user.isGroup === 0"
sg-email="::acl.user.c_email"
size="40"><!-- avatar --></sg-avatar-image>
<div class="sg-list-avatar" ng-show="acl.user.isGroup"><!--list avatar--></div>
<div class="msg-header-content">
<h1 class="sg-md-display-2--thin">{{::acl.user.cn}}</h1>
<h6 class="sg-md-display-2-subheader"><md-icon ng-class="{ 'icon-contacts': acl.folderType == 'AddressBook',
'icon-event': acl.folderType == 'Calendar' }"><!--icon--></md-icon>
{{::acl.folder.name}}
</h6>
</div>
</div>
<!-- only show the fab button on large screens -->
<md-button type="button" class="hide-sm md-fab md-fab-bottom-right md-fab-overlap-bottom"
ng-click="acl.save()">
<md-icon>save</md-icon>
</md-button>
</md-toolbar>
<md-content class="md-flex md-static">
<div class="viewer">
<div layout="row">
<md-icon>search</md-icon>
<md-autocomplete
class="md-flex"
md-input-name="addUser"
md-search-text="acl.searchText"
md-selected-item="acl.userToAdd"
md-selected-item-change="acl.addUser(user)"
md-items="user in acl.userFilter(acl.searchText)"
md-item-text="user.empty"
md-min-length="3"
md-delay="300"
md-no-cache="true"
label:md-floating-label="Add User">
<md-item-template>
<span class="md-contact-suggestion">
<span class="md-contact-name"
md-highlight-text="acl.searchText"
md-highlight-flags="^i">{{user.cn}}</span>
<span class="md-contact-email"
md-highlight-text="acl.searchText"
md-highlight-flags="^i">{{user.c_email}}</span>
</span>
</md-item-template>
</md-autocomplete>
</div>
<md-card ng-repeat="user in acl.users | orderBy:['userClass', 'displayName']"
class="sg-collapsed"
ng-class="{ 'sg-expanded': user.uid == acl.selectedUid }">
<md-button ng-click="acl.selectUser(user)">
<div layout="row" layout-align="start center" class="md-flex">
<span class="card-picture" ng-switch="user.userClass">
<div ng-switch-when="normal-user">
<sg-avatar-image class="md-avatar"
sg-email="user.c_email"
size="40"><!-- avatar --></sg-avatar-image>
</div>
<div ng-switch-when="normal-group" class="md-avatar sg-avatar-list"><!-- normal-group --></div>
<div ng-switch-when="public-user" class="md-avatar sg-avatar-list"><!-- public-user --></div>
</span>
<div class="sg-tile-content">
<div class="sg-md-subhead"><div>{{user.cn}}</div></div>
<div class="sg-md-body"><div>{{user.c_email}}</div></div>
</div>
<md-button class="md-icon-button md-secondary" type="button"
ng-click="acl.removeUser(user)"
ng-hide="user.uid != acl.selectedUid || user.$isSpecial()">
<md-icon>delete</md-icon>
</md-button>
</div>
</md-button>
<md-card-content id="AccessRightList" ng-show="user.uid == acl.selectedUid">
<var:if condition="canSubscribeUsers">
<md-checkbox ng-model="user.isSubscribed"
label:arial-label="Subscribe User"
ng-disabled="user.wasSubscribed"
ng-true-value="1"
ng-false-value="0"
ng-hide="user.$isSpecial()">
<var:string label:value="Subscribe User"/>
</md-checkbox>
</var:if>
<div ng-include="acl.getTemplate()"></div>
<!-- <script type="text/ng-template" id="UIxContactsUserRightsEditor">
<var:component className="UIxContactsUserRightsEditor" />
</script>
<script type="text/ng-template" id="UIxCalUserRightsEditor">
<var:component className="UIxCalUserRightsEditor" />
</script> -->
</md-card-content>
</md-card>
</div>
</md-content>
</div>
</container>
@@ -5,11 +5,32 @@
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">-->
<div layout="column" class="layout-fill">
<md-toolbar class="md-whiteframe-z1">
<div class="md-toolbar-tools">
<md-button class="sg-icon-button"
label:aria-label="Cancel"
ng-click="editor.cancel()">
<md-icon>close</md-icon>
</md-button>
<div class="md-flex"><!-- spacer --></div>
<md-button class="sg-icon-button"
label:aria-label="Reset"
ng-click="editor.reset()">
<md-icon>undo</md-icon>
</md-button>
<md-button class="sg-icon-button"
label:aria-label="Save"
ng-click="editor.save(editor.card.$isCard()?cardForm:listForm)">
<md-icon>save</md-icon>
</md-button>
</div>
</md-toolbar>
<md-content class="md-flex md-static">
<div layout="column" class="viewer 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>
<h1 class="sg-md-display-2--thin" ng-bind-html="editor.card.$fullname()"><!-- fullname --></h1>
<h6 class="sg-md-display-2-subheader--thin">{{editor.card.$description()}}</h6>
</hgroup>
<!-- contact editor -->
@@ -21,7 +42,7 @@
</label>
<input type="text" ng-maxlength="30" ng-model="editor.card.c_cn"/>
</md-input-container>
<!-- todo: look for better reset/normalization. Semanticaly this should be a fieldset, but content doesn't flex properly du to browser styles-->
<!-- todo: look for better reset/normalization. Semanticaly this should be a fieldset, but content doesn't flex properly du to browser styles -->
<div id="contact-identification" class="sg-fieldset" layout="row" layout-sm="column">
<md-input-container flex="40">
<label>
@@ -43,19 +64,25 @@
</md-input-container>
</div>
<div class="sg-fieldset" layout="row" layout-sm="column">
<md-input-container>
<div id="contact-identification" class="sg-fieldset" layout="row" layout-sm="column">
<md-input-container flex="40">
<label>
<var:string label:value="Organization"/>
</label>
<input type="text" ng-model="editor.card.c_org"/>
</md-input-container>
<md-input-container>
<md-input-container flex="40">
<label>
<var:string label:value="Title"/>
</label>
<input type="text" ng-model="editor.card.title"/>
</md-input-container>
<md-input-container flex="20">
<label>
<var:string label:value="Role"/>
</label>
<input type="text" ng-model="editor.card.role"/>
</md-input-container>
</div>
<!-- org units -->
@@ -101,9 +128,11 @@
<div class="section">
<div class="attr" ng-repeat="email in editor.card.emails">
<div class="md-layout-margin" layout="row" layout-align="space-between end">
<md-select ng-model="email.type" label:placeholder="Type">
<md-option ng-repeat="type in ::editor.allEmailTypes" ng-value="type">{{ type }}</md-option>
</md-select>
<md-input-container flex="20">
<md-select ng-model="email.type" label:placeholder="Type">
<md-option ng-repeat="type in ::editor.allEmailTypes" ng-value="type">{{ type }}</md-option>
</md-select>
</md-input-container>
<md-input-container>
<label>
<var:string label:value="Email Address"/>
@@ -126,13 +155,38 @@
</div>
</div>
<div class="section">
<div layout="row" layout-align="space-between end" ng-show="editor.card.c_screenname != null">
<md-input-container>
<label class="pseudo-input-label">
<var:string label:value="Screen Name"/>
</label>
<input type="text" ng-model="editor.card.c_screenname"/>
</md-input-container>
<md-button class="sg-icon-button" type="button" ng-click="editor.card.$delete('c_screenname', -1)">
<md-icon>remove_circle</md-icon>
</md-button>
</div>
<div class="md-layout-margin" layout="row" layout-align="start center" ng-show="editor.card.c_screenname == null">
<md-button class="sg-icon-button" type="button" ng-click="editor.addScreenName($event)">
<md-icon>add_circle</md-icon>
</md-button>
<label class="button-label">
<var:string label:value="Add Screen Name"/>
</label>
</div>
</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>
<div class="pseudo-input-container">
<label class="pseudo-input-label">
<var:string label:value="Birthday"/>
</label>
<md-datepicker class="pseudo-input-field"
ng-model="editor.card.birthday"><!-- birthday --></md-datepicker>
</div>
<md-button class="sg-icon-button" type="button" ng-click="editor.card.$delete('birthday', -1)">
<md-icon>remove_circle</md-icon>
</md-button>
@@ -151,9 +205,11 @@
<div class="section">
<div class="attr" ng-repeat="phone in editor.card.phones">
<div class="md-layout-margin" layout="row" layout-align="space-between end">
<md-select ng-model="phone.type" label:placeholder="Type">
<md-option ng-repeat="type in ::editor.allTelTypes" ng-value="type">{{ type }}</md-option>
</md-select>
<md-input-container flex="20">
<md-select ng-model="phone.type" label:placeholder="Type">
<md-option ng-repeat="type in ::editor.allTelTypes" ng-value="type">{{ type }}</md-option>
</md-select>
</md-input-container>
<md-input-container>
<label>
<var:string label:value="Phone Number"/>
@@ -181,9 +237,11 @@
<div class="section">
<div class="attr" ng-repeat="url in editor.card.urls">
<div class="md-layout-margin" layout="row" layout-align="space-between end">
<md-select ng-model="url.type" label:placeholder="Type">
<md-option ng-repeat="type in ::editor.allUrlTypes" ng-value="type">{{ type }}</md-option>
</md-select>
<md-input-container flex="20">
<md-select ng-model="url.type" label:placeholder="Type">
<md-option ng-repeat="type in ::editor.allUrlTypes" ng-value="type">{{ type }}</md-option>
</md-select>
</md-input-container>
<md-input-container>
<label>
<var:string label:value="URL"/>
@@ -209,9 +267,11 @@
<div class="section">
<div class="attr" ng-repeat="address in editor.card.addresses">
<div layout="row" layout-align="center end">
<md-select ng-model="address.type" label:placeholder="Type">
<md-option ng-repeat="type in ::editor.allAddressTypes" ng-value="type">{{ type }}</md-option>
</md-select>
<md-input-container flex="20">
<md-select ng-model="address.type" label:placeholder="Type">
<md-option ng-repeat="type in ::editor.allAddressTypes" ng-value="type">{{ type }}</md-option>
</md-select>
</md-input-container>
<md-input-container>
<label>
<var:string label:value="street"/>
@@ -287,22 +347,10 @@
</label>
<textarea ng-model="editor.card.note"><!-- note --></textarea>
</md-input-container>
<div class="fieldset md-layout-margin" layout="row" layout-align="end center">
<md-button type="button" ng-click="editor.cancel()">
<var:string label:value="Cancel"/>
</md-button>
<md-button type="button" ng-click="editor.reset()">
<var:string label:value="Reset"/>
</md-button>
<md-button class="md-primary md-hue-3" type="submit">
<var:string label:value="Save"/>
</md-button>
</div>
</form>
<!-- list editor -->
<form name="listForm" ng-if="editor.card.$isList()" ng-submit="editor.save(listForm)">
<form name="listForm" ng-show="editor.card.$isList()" ng-submit="editor.save(listForm)">
<md-input-container>
<label>
<var:string label:value="Display"/>
@@ -339,22 +387,8 @@
filter-selected="false"
label:placeholder="Add Member"><!-- members --></md-contact-chips>
</div>
<div class="fieldset md-layout-margin" layout="row" layout-align="end center">
<md-button type="button" ng-click="editor.cancel()">
<var:string label:value="Cancel"/>
</md-button>
<md-button type="button" ng-click="editor.reset()">
<var:string label:value="Reset"/>
</md-button>
<var:if condition="canCreateOrModify">
<md-button class="md-primary md-hue-3" type="submit">
<var:string label:value="Save"/>
</md-button>
</var:if>
</div>
</form>
<!-- </div> -->
</div>
</md-content>
</div>
</container>
@@ -7,7 +7,7 @@
xmlns:label="OGo:label"
>
<md-dialog flex="60" flex-sm="100">
<md-toolbar class="sg-padded">
<md-toolbar>
<md-icon class="material-icons sg-icon-toolbar-bg">link</md-icon>
<div class="md-toolbar-tools">
<div class="pseudo-input-container md-flex">
@@ -20,8 +20,8 @@
</div>
</md-toolbar>
<md-dialog-content>
<div layout="column" layout-padding="layout-padding">
<md-dialog-content class="md-padding">
<div layout="column">
<div class="sg-md-title"><var:string label:value="Authenticated User Access"/></div>
<md-input-container>
<label><var:string label:value="CardDAV URL"/></label>
@@ -0,0 +1,42 @@
<?xml version="1.0" standalone="yes"?>
<!DOCTYPE container>
<container
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-dialog flex="40" flex-md="60" flex-sm="90">
<md-toolbar>
<div class="md-toolbar-tools">
<!-- name -->
<md-input-container>
<label><var:string label:value="Name"/></label>
<input type="text"
class="md-title"
ng-model="properties.addressbook.name"/>
</md-input-container>
<md-button class="md-icon-button" ng-click="properties.close()">
<md-icon aria-label="Close dialog">close</md-icon>
</md-button>
</div>
</md-toolbar>
<md-dialog-content class="md-dialog-content" layout="column">
<md-checkbox
ng-model="properties.addressbook.synchronize"
ng-disabled="properties.addressbook.id == 'personal'"
ng-true-value="1"
ng-false-value="0">
<var:string label:value="Synchronize"/>
</md-checkbox>
</md-dialog-content>
<md-dialog-actions>
<md-button type="button" ng-click="properties.close()"><var:string label:value="Cancel"/></md-button>
<md-button ng-click="properties.saveProperties()"><var:string label:value="Save"/></md-button>
</md-dialog-actions>
</md-dialog>
</container>
+231 -132
View File
@@ -9,7 +9,7 @@
className="UIxPageFrame"
title="title"
const:userDefaultsKeys="SOGoContactsCategories"
const:jsFiles="Common.js, Preferences.services.js, Contacts.js, Contacts.services.js, vendor/angular-file-upload.min.js">
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">
<script type="text/javascript">
var contactFolders = <var:string value="contactFolders" const:escapeHTML="NO" />;
</script>
@@ -20,13 +20,15 @@
<script type="text/ng-template" id="UIxContactFoldersView">
<!-- Sidenav -->
<md-sidenav id="left-sidenav" class="md-sidenav-left md-whiteframe-z1" md-component-id="left" md-is-locked-open="isGtMedium" layout="column">
<md-sidenav class="md-sidenav-left md-whiteframe-z1" layout="column"
md-component-id="left" md-is-locked-open="isGtMedium"
ng-class="{ 'sg-closed': leftIsClose }">
<var:component className="UIxSidenavToolbarTemplate" />
<!-- <div style="position: relative; display: flex;"> -->
<md-content md-scroll-y="md-scroll-y">
<md-content md-scroll-y="md-scroll-y" class="md-flex md-hue-2">
<!-- User's addressbooks -->
<section>
<md-subheader class="sg-md-subheader">
<md-subheader class="sg-md-subheader md-hue-2">
<div layout="row" layout-align="space-between center">
<span><var:string label:value="Address Books"/></span>
<md-button class="sg-icon-button"
@@ -38,16 +40,16 @@
</md-subheader>
<md-list>
<md-list-item ng-repeat="folder in app.service.$addressbooks track by folder.id"
ng-click="app.select(folder)"
ng-click="app.select($event, folder)"
ng-dblclick="app.edit(folder)"
ui-sref="app.addressbook({addressbookId: folder.id})"
ui-sref-active="sg-active">
ui-sref-active="md-default-theme md-background md-bg md-hue-1">
<md-icon>contacts</md-icon>
<p class="sg-item-name"
ng-show="app.editMode!=folder.id">{{folder.name}}</p>
<md-input-container class="md-flex md-tile-content"
<md-input-container class="md-flex"
ng-show="app.editMode == folder.id">
<input class="folder-name" type="text"
<input class="sg-item-name" type="text"
label:aria-label="Name of the Address Book"
ng-model="folder.name"
ng-cloak="ng-cloak"
@@ -67,7 +69,7 @@
<var:string label:value="Rename"/>
</md-button>
</md-menu-item>
<md-menu-item>
<md-menu-item ng-show="folder.id != 'personal'">
<md-button type="button" ng-click="app.confirmDelete()">
<var:string label:value="Delete"/>
</md-button>
@@ -94,6 +96,11 @@
<var:string label:value="Sharing..."/>
</md-button>
</md-menu-item>
<md-menu-item>
<md-button type="button" ng-click="app.showProperties(folder)">
<var:string label:value="Properties"/>
</md-button>
</md-menu-item>
</md-menu-content>
</md-menu>
</md-list-item>
@@ -101,7 +108,7 @@
</section>
<!-- Subscriptions -->
<section>
<md-subheader class="sg-md-subheader">
<md-subheader class="sg-md-subheader md-hue-2">
<div layout="row" layout-align="space-between center">
<span><var:string label:value="Subscriptions"/></span>
<md-button class="sg-icon-button"
@@ -114,16 +121,16 @@
</md-subheader>
<md-list>
<md-list-item ng-repeat="folder in app.service.$subscriptions track by folder.id"
ng-click="app.select(folder)"
ng-click="app.select($event, folder)"
ng-dblclick="app.edit(folder)"
ui-sref="app.addressbook({addressbookId: folder.id})"
ui-sref-active="sg-active">
ui-sref-active="md-default-theme md-background md-bg md-hue-1">
<md-icon>contacts</md-icon>
<p class="sg-item-name"
ng-show="editMode!=folder.id">{{folder.name}}</p>
<md-input-container class="md-flex md-tile-content"
<md-input-container class="md-flex"
ng-show="app.editMode==folder.id">
<input class="folder-name" type="text"
<input class="sg-item-name" type="text"
label:aria-label="Name of the Address Book"
ng-model="folder.name"
ng-cloak="ng-cloak"
@@ -148,6 +155,12 @@
<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.showProperties(folder)">
<var:string label:value="Properties"/>
</md-button>
</md-menu-item>
</md-menu-content>
</md-menu>
</md-list-item>
@@ -155,14 +168,14 @@
</section>
<!-- Remote/domain addressbooks -->
<section>
<md-subheader class="sg-md-subheader md-padding">
<md-subheader class="sg-md-subheader md-hue-2">
<var:string label:value="Global Addressbooks"/>
</md-subheader>
<md-list>
<md-list-item ng-repeat="folder in app.service.$remotes track by folder.id"
ng-click="app.select(folder)"
ng-click="app.select($event, folder)"
ui-sref="app.addressbook({addressbookId: folder.id})"
ui-sref-active="sg-active">
ui-sref-active="md-default-theme md-background md-bg md-hue-1">
<md-icon>public</md-icon>
<p class="sg-item-name">{{folder.name}}</p>
</md-list-item>
@@ -176,22 +189,24 @@
</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 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">
<md-toolbar layout="row" layout-align="space-between center" class="toolbar-main">
<var:component className="UIxTopnavToolbarTemplate" />
</md-toolbar>
<div class="view-list" layout="row" layout-align="space-between center"
ng-hide="addressbook.mode.search">
<div class="sg-toolbar-group">
<div layout="row" class="md-flex">
<div class="view-list" layout="column">
<!-- single-selection toolbar -->
<md-toolbar class="md-whiteframe-z1"
ng-show="addressbook.selectedFolder.$selectedCount() == 0">
<!-- sort mode (default) -->
<div class="md-toolbar-tools" ng-hide="addressbook.mode.search">
<md-button class="sg-icon-button" label:aria-label="Search"
ng-click="addressbook.mode.search = true">
<md-icon>search</md-icon>
</md-button>
</div>
<div class="sg-toolbar-group-last">
<div class="sg-folder-name">{{addressbook.selectedFolder.name}}</div>
<md-menu>
<md-button class="sg-icon-button" label:aria-label="Sort"
ng-click="$mdOpenMenu()">
@@ -204,6 +219,18 @@
<!-- selected --></md-icon> <var:string label:value="Name"/>
</md-button>
</md-menu-item>
<md-menu-item>
<md-button ng-click="addressbook.sort('c_sn')">
<md-icon ng-class="{ 'icon-check': addressbook.sortedBy('c_sn') }">
<!-- selected --></md-icon> <var:string label:value="Lastname"/>
</md-button>
</md-menu-item>
<md-menu-item>
<md-button ng-click="addressbook.sort('c_givenname')">
<md-icon ng-class="{ 'icon-check': addressbook.sortedBy('c_givenname') }">
<!-- selected --></md-icon> <var:string label:value="Firstname"/>
</md-button>
</md-menu-item>
<md-menu-item>
<md-button ng-click="addressbook.sort('c_mail')">
<md-icon ng-class="{ 'icon-check': addressbook.sortedBy('c_mail') }">
@@ -233,8 +260,9 @@
</md-menu-item>
<md-menu-divider> <!-- divider --></md-menu-divider>
<md-menu-item >
<md-button ng-click="addressbook.sort(addressbook.selectedFolder.constructor.$query.sort)">
<md-button ng-href="#">
<md-checkbox
ng-change="addressbook.sort(addressbook.selectedFolder.constructor.$query.sort)"
ng-model="addressbook.selectedFolder.constructor.$query.asc"
ng-true-value="0"
ng-false-value="1"><var:string label:value="Descending Order"/></md-checkbox>
@@ -246,122 +274,153 @@
<md-icon>refresh</md-icon>
</md-button>
</div>
</div>
<!-- search mode -->
<div class="view-list sg-padded--right sg-toolbar-search" layout="row" layout-align="space-between center"
ng-show="addressbook.mode.search"
sg-search="addressbook.selectedFolder.$filter(searchText, { search: searchField })">
<md-button class="sg-icon-button"
sg-search-cancel="addressbook.cancelSearch()"
label:aria-label="Back">
<md-icon>arrow_back</md-icon>
</md-button>
<md-input-container>
<input name="folderSearch" type="search" />
</md-input-container>
<md-input-container>
<md-select>
<md-option value="name_or_address" selected="selected"><var:string label:value="Name or Email"/></md-option>
<md-option value="category"><var:string label:value="Category"/></md-option>
<md-option value="organization"><var:string label:value="Organization"/></md-option>
</md-select>
</md-input-container>
</div>
</div>
<!-- search mode -->
<div class="md-toolbar-tools sg-toolbar-secondary"
ng-show="addressbook.mode.search"
sg-search="addressbook.selectedFolder.$filter(searchText, { search: searchField })">
<md-button class="sg-icon-button"
sg-search-cancel="addressbook.cancelSearch()"
label:aria-label="Back">
<md-icon>arrow_back</md-icon>
</md-button>
<md-input-container md-no-float="md-no-float">
<input name="folderSearch" type="search" label:placeholder="Search"/>
</md-input-container>
<md-input-container flex="25">
<md-select>
<md-option value="name_or_address" selected="selected"><var:string label:value="Name or Email"/></md-option>
<md-option value="category"><var:string label:value="Category"/></md-option>
<md-option value="organization"><var:string label:value="Organization"/></md-option>
</md-select>
</md-input-container>
</div>
</md-toolbar>
<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-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>
<!-- multiple selection mode -->
<md-toolbar class="md-whiteframe-z1 md-hue-1 sg-toolbar-secondary"
ng-show="addressbook.selectedFolder.$selectedCount() > 0">
<div class="md-toolbar-tools">
<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 class="md-flex"><!-- spacer --></div>
<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-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-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>
<var:string label:value="Write"/>
<md-menu-content width="4">
<md-menu-item>
<md-button class="md-primary" ng-disabled="true"><var:string label:value="Copy To"/></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-item>
<md-menu-item>
<md-button ng-click="addressbook.saveSelectedCards()">
<var:string label:value="Export"/>
</md-button>
</md-menu-item>
</md-menu-content>
</md-menu>
</div>
</md-toolbar>
<div layout="row" class="md-flex">
<div class="view-list" layout="column">
<md-menu-content width="2">
<md-menu-item>
<md-button ng-click="addressbook.newMessageWithSelectedCards($event)">
<var:string label:value="Write"/>
</md-button>
</md-menu-item>
<md-menu-item>
<md-button ng-click="addressbook.saveSelectedCards()">
<var:string label:value="Export"/>
</md-button>
</md-menu-item>
</md-menu-content>
</md-menu>
</div>
</md-toolbar>
<md-content id="contactsList" layout="column" class="md-flex">
<header class="sg-md-subheader sg-md-subheader--fixed">
<h2 class="md-default-theme sg-md-subhead-solo fg-sogoBlue-700">
<span ng-show="addressbook.selectedFolder.cards.length > 0">{{addressbook.selectedFolder.cards.length}} <var:string label:value="contacts"/></span>
<span ng-show="addressbook.selectedFolder.cards.length == 0"><var:string label:value="No contact"/></span>
</h2>
</header>
<md-subheader ng-show="addressbook.service.$query.value">
<md-button class="md-icon-button hide show-gt-sm" ng-click="toggleLeft()">
<md-icon ng-class="{'md-rotate-180': leftIsClose }">keyboard_arrow_left</md-icon>
</md-button>
<span ng-switch="addressbook.selectedFolder.cards.length">
<span ng-switch-when="0"><var:string label:value="No matching contact"/></span>
<span ng-switch-default="true">{{addressbook.selectedFolder.cards.length}} <var:string label:value="matching contacts"/></span>
</span>
</md-subheader>
<md-subheader ng-hide="addressbook.service.$query.value">
<md-button class="md-icon-button hide show-gt-sm" ng-click="toggleLeft()">
<md-icon ng-class="{'md-rotate-180': leftIsClose }">keyboard_arrow_left</md-icon>
</md-button>
<span ng-switch="addressbook.selectedFolder.isRemote">
<span ng-switch-when="1">
<var:string label:value="Start a search to browse this address book"/>
</span>
<span ng-switch-default="true">
<span ng-switch="addressbook.selectedFolder.cards.length">
<span ng-switch-when="0"><var:string label:value="No contact"/></span>
<span ng-switch-default="true">{{addressbook.selectedFolder.cards.length}} <var:string label:value="contacts"/></span>
</span>
</span>
</span>
</md-subheader>
<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">
<div md-virtual-repeat="currentCard in addressbook.selectedFolder.cards" md-item-size="56">
<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>
<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="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>
ui-sref="app.addressbook.card.view({addressbookId: addressbook.selectedFolder.id, cardId: currentCard.id})"
ui-sref-active="md-default-theme md-background md-bg md-hue-1">
<div class="md-avatar sg-avatar-selected"
ng-if="currentCard.selected"
ng-click="addressbook.toggleCardSelection($event, currentCard)">
<!-- selected avatar -->
</div>
<sg-avatar-image class="md-avatar"
ng-if="addressbook.notSelectedComponent(currentCard, 'vcard')"
ng-click="addressbook.toggleCardSelection($event, currentCard)"
sg-email="currentCard.$preferredEmail(addressbook.selectedFolder.constructor.$query)"
size="40">
<!-- contact avatar -->
</sg-avatar-image>
<div class="md-avatar sg-avatar-list"
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-subhead">
<div ng-bind-html="currentCard.$fullname()"><!-- cn --></div>
</div>
<div class="sg-md-body">
<div>{{currentCard.$preferredEmail(addressbook.selectedFolder.constructor.$query)}}</div>
</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"
@@ -371,10 +430,16 @@
</md-content>
</div>
<div id="detailView" class="view-detail ng-cloak" layout="column">
<md-card class="viewer" ui-view="card"><!-- card view --></md-card>
<div id="detailView" class="view-detail md-default-theme md-background md-bg md-hue-1"
layout="column" layout-align="start center"
ng-class="{ 'sg-close': !addressbook.selectedFolder.selectedCard }"
ui-view="card">
<md-toolbar class="md-whiteframe-z1 hide-sm"><!-- empty toolbar --></md-toolbar>
<md-content class="hide-xs md-flex layout-fill md-hue-1"
layout="column" layout-align="center center">
<div class="md-default-theme md-background md-fg md-hue-3 sg-md-title"><var:string label:value="No contact selected"/></div>
</md-content>
</div>
</div>
</script>
@@ -383,6 +448,40 @@
<var:component className="UIxContactsUserRightsEditor" />
</script>
<!-- modal for cards import -->
<script type="text/ng-template" id="UIxContactsImportDialog">
<md-dialog flex="40" flex-sm="100" label:aria-label="Import Cards">
<md-toolbar>
<div class="md-toolbar-tools">
<md-icon class="material-icons sg-icon-toolbar-bg">import_export</md-icon>
<div class="md-flex">
<div class="sg-md-title"><var:string label:value="Import Cards"/></div>
</div>
<md-button class="md-icon-button" ng-click="$CardsImportDialogController.close()">
<md-icon aria-label="Close dialog">close</md-icon>
</md-button>
</div>
</md-toolbar>
<md-dialog-content class="md-dialog-content">
<p><var:string label:value="Select a vCard or LDIF file."/></p>
</md-dialog-content>
<md-dialog-actions>
<md-progress-circular class="md-accent"
md-mode="determinate"
md-diameter="20px"
ng-show="$CardsImportDialogController.uploader.isUploading"
ng-value="$CardsImportDialogController.uploader.progress"><!-- progress --></md-progress-circular>
<label class="md-button" for="file-input" ng-hide="$CardsImportDialogController.uploader.isUploading">
<span><var:string label:value="Upload"/></span>
</label>
<input id="file-input" type="file" class="ng-hide"
nv-file-select="nv-file-select"
uploader="$CardsImportDialogController.uploader"/>
<!-- <md-button ng-disabled="uploader.queue.length == 0" ng-click="upload()"><var:string label:value="Upload"/></md-button> -->
</md-dialog-actions>
</md-dialog>
</script>
<script type="text/ng-template" id="UIxContactViewTemplate">
<var:component className="UIxContactViewTemplate" />
</script>
+151 -136
View File
@@ -3,52 +3,33 @@
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-card-content>
<header class="msg-header">
<div ng-show="editor.card.tag == 'vcard'">
<sg-avatar-image class="md-tile-left"
sg-email="editor.card.$preferredEmail()"
sg-src="editor.card.photoURL"
size="48"><!-- avatar --></sg-avatar-image>
</div>
<div class="sg-list-avatar" ng-show="editor.card.tag == 'vlist'">
<!--list avatar-->
</div>
<div class="msg-header-content">
<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>
<md-chips ng-model="editor.card.categories"
class="sg-readonly" readonly="true">
<md-chip-template>
{{$chip.value}}
</md-chip-template>
</md-chips>
</div>
<div class="sg-icon-bar--vertical">
<md-button class="sg-icon-button show-sm"
label:aria-label="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"
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>
</md-button>
xmlns:label="OGo:label">
<div layout="column" class="layout-fill">
<md-toolbar class="md-whiteframe-z1">
<div class="md-toolbar-tools">
<md-button class="sg-icon-button hide show-sm"
label:aria-label="Close"
ng-click="editor.close()">
<md-icon>close</md-icon>
</md-button>
<div class="md-flex"><!-- spacer --></div>
<md-button class="sg-icon-button"
label:aria-label="Edit"
ng-show="editor.currentFolder.acls.objectEditor"
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>
</md-button>
<md-menu>
<md-button label:aria-label="More contact options" class="sg-icon-button" ng-click="$mdOpenMenu($event)">
<md-button label:aria-label="More options" class="sg-icon-button" ng-click="$mdOpenMenu($event)">
<md-icon>more_vert</md-icon>
</md-button>
<md-menu-content>
@@ -66,109 +47,143 @@
</md-menu-item>
</md-menu-content>
</md-menu>
</div>
</header>
<section class="msg-body">
<div class="pseudo-input-container" ng-show="editor.card.$birthday().length">
<div class="key">
<label class="pseudo-input-label">
<var:string label:value="Birthday"/>
</label>
</div>
</md-toolbar>
<md-content class="md-flex md-static">
<div layout="column" class="viewer md-padding">
<header class="msg-header">
<div ng-show="editor.card.c_component == 'vcard'">
<sg-avatar-image class="md-tile-left"
sg-email="editor.card.$preferredEmail()"
sg-src="editor.card.photoURL"
size="40"><!-- avatar --></sg-avatar-image>
</div>
<div class="pseudo-input-field">
<span>{{editor.card.$birthday()}}</span>
<div class="sg-list-avatar" ng-show="editor.card.c_component == 'vlist'">
<!--list avatar-->
</div>
</div>
<div class="msg-header-content">
<h1 class="sg-md-display-2--thin" ng-bind-html="editor.card.$fullname()"><!-- fullname --></h1>
<h6 class="sg-md-display-2-subheader--thin">{{editor.card.$description()}}</h6>
<md-chips ng-model="editor.card.categories"
class="sg-readonly" readonly="true">
<md-chip-template>
{{$chip.value}}
</md-chip-template>
</md-chips>
</div>
</header>
<section class="msg-body">
<!-- list members -->
<div class="section" ng-show="editor.card.refs.length > 0">
<label class="pseudo-input-label">
<var:string label:value="Members"/>
</label>
<md-list>
<md-list-item class="md-3-line" ng-repeat="ref in editor.card.refs track by ref.reference">
<sg-avatar-image class="md-tile-left"
sg-email="ref.$preferredEmail()"
size="48">
<!-- contact avatar -->
</sg-avatar-image>
<div class="md-list-item-text">
<h3>
<a ui-sref="app.addressbook.card.view({addressbookId: editor.currentFolder.id, cardId: ref.reference})">
{{ ref.$fullname() }}
</a>
</h3>
<h4 ng-show="ref.email">
<a ui-sref="mailto:{{ref.email}}" ng-class="ng-scope">
{{ ref.email }}
</a>
</h4>
</div>
</md-list-item>
</md-list>
</div>
<div class="section" ng-show="editor.card.emails.length > 0">
<div class="pseudo-input-container" ng-repeat="email in editor.card.emails">
<div class="pseudo-input-container" ng-show="editor.card.$birthday().length">
<div class="key">
<label class="pseudo-input-label"><var:entity const:name="nbsp"/>{{email.type}}</label>
</div>
<div class="pseudo-input-field">
<a href="mailto:{{email.value}}">{{email.value}}</a>
</div>
</div>
</div>
<div class="section" ng-show="editor.card.phones.length > 0">
<div class="pseudo-input-container" ng-repeat="phone in editor.card.phones">
<div class="key">
<label class="pseudo-input-label">{{phone.type}}</label>
</div>
<div class="pseudo-input-field">
<a href="tel:{{phone.value}}">{{phone.value}}</a>
</div>
</div>
</div>
<div class="section" ng-show="editor.card.urls">
<div class="pseudo-input-container" ng-repeat="url in editor.card.urls">
<div class="key">
<label class="pseudo-input-label"><var:entity const:name="nbsp"/>{{url.type}}
<label class="pseudo-input-label">
<var:string label:value="Birthday"/>
</label>
</div>
<div class="pseudo-input-field">
<a href="#" ng-href="{{url.value}}">{{url.value}}</a>
</div>
</div>
</div>
<div class="section" ng-show="editor.card.addresses">
<div class="pseudo-input-container" ng-repeat="address in editor.card.addresses">
<div class="key">
<label class="pseudo-input-label">{{address.type}}</label>
</div>
<div class="pseudo-input-field">
<div sg-address="address"><!-- address --></div>
<span>{{editor.card.$birthday()}}</span>
</div>
</div>
</div>
<div class="pseudo-input-container" ng-show="editor.card.note">
<div class="key">
<!-- list members -->
<div class="section" ng-show="editor.card.refs.length > 0">
<label class="pseudo-input-label">
<var:string label:value="Note"/>
<var:string label:value="Members"/>
</label>
<md-list>
<md-list-item class="md-3-line" ng-repeat="ref in editor.card.refs track by ref.reference">
<sg-avatar-image class="md-tile-left"
sg-email="ref.$preferredEmail()"
size="48">
<!-- contact avatar -->
</sg-avatar-image>
<div class="md-list-item-text">
<h3>
<a ui-sref="app.addressbook.card.view({addressbookId: editor.currentFolder.id, cardId: ref.reference})">
{{ ref.$fullname() }}
</a>
</h3>
<h4 ng-show="ref.email">
<a ui-sref="mailto:{{ref.email}}" ng-class="ng-scope">
{{ ref.email }}
</a>
</h4>
</div>
</md-list-item>
</md-list>
</div>
<div class="pseudo-input-field">
<div ng-bind-html="editor.card.note"><!-- note --></div>
</div>
</div>
</section>
</md-card-content>
<div class="section" ng-show="editor.card.emails.length > 0">
<div class="pseudo-input-container" ng-repeat="email in editor.card.emails">
<div class="key">
<label class="pseudo-input-label"><var:entity const:name="nbsp"/>{{email.type}}</label>
</div>
<div class="pseudo-input-field">
<a href="#" ng-bind="email.value"
ng-click="addressbook.newMessageWithRecipient($event, email.value, editor.card.$fullname())"><!-- recipient --></a>
</div>
</div>
</div>
<div class="section" ng-show="editor.card.c_screenname">
<div class="pseudo-input-container">
<div class="key">
<label class="pseudo-input-label"><var:string label:value="Screen Name"/></label>
</div>
<div class="pseudo-input-field">{{editor.card.c_screenname}}</div>
</div>
</div>
<div class="section" ng-show="editor.card.phones.length > 0">
<div class="pseudo-input-container" ng-repeat="phone in editor.card.phones">
<div class="key">
<label class="pseudo-input-label">{{phone.type}}</label>
</div>
<div class="pseudo-input-field">
<a href="tel:{{phone.value}}">{{phone.value}}</a>
</div>
</div>
</div>
<div class="section" ng-show="editor.card.urls">
<div class="pseudo-input-container" ng-repeat="url in editor.card.urls">
<div class="key">
<label class="pseudo-input-label"><var:entity const:name="nbsp"/>{{url.type}}
</label>
</div>
<div class="pseudo-input-field">
<a href="#" target="_new" ng-href="{{url.value}}">{{url.value}}</a>
</div>
</div>
</div>
<div class="section" ng-show="editor.card.addresses">
<div class="pseudo-input-container" ng-repeat="address in editor.card.addresses">
<div class="key">
<label class="pseudo-input-label">{{address.type}}</label>
</div>
<div class="pseudo-input-field">
<div sg-address="address"><!-- address --></div>
</div>
</div>
</div>
<div class="pseudo-input-container" ng-show="editor.card.note">
<div class="key">
<label class="pseudo-input-label">
<var:string label:value="Note"/>
</label>
</div>
<div class="pseudo-input-field">
<div ng-bind-html="editor.card.note"><!-- note --></div>
</div>
</div>
</section>
</div>
</md-content>
</div>
</container>
@@ -7,8 +7,15 @@
xmlns:label="OGo:label"
xmlns:uix="OGo:uix">
<md-dialog flex="50" flex-sm="100">
<md-dialog-content>
<h2 class="md-title"><var:string label:value="Subscribe to a shared folder"/></h2>
<md-toolbar>
<div class="md-toolbar-tools">
<div class="sg-md-title md-flex"><var:string label:value="Subscribe to a shared folder"/></div>
<md-button class="md-icon-button" ng-click="subscribe.close()">
<md-icon label:aria-label="Close">close</md-icon>
</md-button>
</div>
</md-toolbar>
<md-dialog-content class="md-dialog-content">
<md-input-container>
<label><md-icon>search</md-icon><var:string label:value="Search User"/></label>
<input type="input"
@@ -23,18 +30,17 @@
<div layout="row" layout-align="start center" class="md-flex">
<span class="card-picture" ng-switch="user.isGroup">
<div ng-switch-when="0">
<sg-avatar-image class="md-tile-left"
<sg-avatar-image class="md-avatar"
sg-email="user.c_email"
size="48"><!-- avatar --></sg-avatar-image>
size="40"><!-- avatar --></sg-avatar-image>
</div>
<div ng-switch-when="1" class="sg-list-avatar"><!-- normal-group --></div>
</span>
<div class="sg-tile-content">
<div class="sg-md-subhead-multi">{{user.cn}} {{user.userClass}}</div>
<div class="sg-md-body-multi">{{user.c_email}}</div>
<div class="sg-md-subhead"><div>{{user.cn}}</div></div>
<div class="sg-md-body"><div>{{user.c_email}}</div></div>
</div>
<md-icon ng-class="{ 'icon-expand-more': user.uid != subscribe.selectedUser.uid,
'icon-expand-less': user.uid == subscribe.selectedUser.uid }"><!--icon--></md-icon>
<md-icon ng-class="{'md-rotate-180': user.uid == subscribe.selectedUser.uid}">expand_more</md-icon>
</div>
</md-button>
<md-card-content ng-show="user == subscribe.selectedUser">
@@ -6,7 +6,7 @@
xmlns:rsrc="OGo:url"
xmlns:label="OGo:label"
xmlns:uix="OGo:uix">
<div class="addressbookUserRights" layout="column">
<div layout="column">
<md-checkbox name="canViewObjects"
ng-model="acl.selectedUser.rights.canViewObjects"
@@ -79,7 +79,7 @@
<var:string label:value="Delegate ..." />
</md-button>
<div class="md-actions" layout="row"
<md-dialog-actions layout="row"
layout-align="start center"
ng-show="delegateInvitation == true">
@@ -104,7 +104,7 @@
<md-button class="md-primitive"
ng-click="iCalendarAction('delegate')"
ng-disabled="!delegatedTo || delegatedTo.length == 0"><var:string label:value="OK"/></md-button>
</div>
</md-dialog-actions>
</var:if>
<!-- TODO - should we re-enable this? It never
worked in v2!
@@ -251,13 +251,15 @@
<!-- 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"
ng-model="part.participants"
ng-model="::part.participants"
readonly="true">
<md-chip-template>
<div class="md-contact-avatar"><img src="#" ng-src="{{$chip.image}}" alt="{{$chip.name}}"/></div>
<div class="md-contact-avatar">
<sg-avatar-image sg-email="$chip.email" size="32"><!-- avatar --></sg-avatar-image>
</div>
<div class="md-contact-name">{{$chip.name}}</div>
<md-icon ng-class="'icon-' + $chip.status"><!-- partstat --></md-icon>
</md-chip-template>
</md-chip-template>
</md-chips>
</div>
</md-list>
@@ -11,16 +11,18 @@
var:title="filenameForDisplay"
class="md-card-image"></img>
<md-card-content>
<p class="md-caption">
<var:string value="filenameForDisplay" /><br/>
<var:string value="bodyInfo.size" formatter="sizeFormatter"/>
<p class="md-caption" var:title="filenameForDisplay">
<var:string value="filenameForDisplay" />
</p>
</md-card-content>
<div class="md-actions" layout="row" layout-align="end center">
<md-dialog-actions layout="row" layout-align="start center">
<div class="md-flex sg-attachment-size">
<var:string value="bodyInfo.size" formatter="sizeFormatter"/>
</div>
<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>
</md-dialog-actions>
</md-card>
</container>
@@ -1,18 +1,20 @@
<?xml version="1.0" standalone="yes"?>
<!DOCTYPE div>
<div xmlns="http://www.w3.org/1999/xhtml"
<container 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-card>
<md-card-content>
<img var:src="mimeImageURL"/>
<p class="md-caption">
<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-card-content>
<img var:src="mimeImageURL"/>
<p class="md-caption">
<var:string value="filenameForDisplay"/>
</p>
</md-card-content>
<md-dialog-actions layout="row" layout-align="end center">
<div class="md-flex sg-attachment-size">
<var:string value="bodyInfo.size" formatter="sizeFormatter"/>
</div>
<md-button class="sg-icon-button" var:href="pathToAttachment" target="_blank">
<md-tooltip md-direction="left"><var:string label:value="View Attachment"/></md-tooltip>
<md-icon>open_in_browser</md-icon>
@@ -21,7 +23,7 @@
<md-tooltip md-direction="left"><var:string label:value="Save Attachment"/></md-tooltip>
<md-icon>save</md-icon>
</md-button>
</div>
</md-dialog-actions>
<!-- DEBUG
<pre><var:string value="bodyInfo"/></pre>
@@ -43,4 +45,4 @@
-->
</md-card>
</div>
</container>
+202 -169
View File
@@ -5,201 +5,234 @@
xmlns:const="http://www.skyrix.com/od/constant"
xmlns:label="OGo:label">
<md-dialog flex="80" flex-sm="100">
<md-toolbar class="md-padding">
<md-dialog class="sg-mail-editor" flex="80" flex-sm="100">
<md-toolbar>
<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-icon class="sg-icon-toolbar-bg">edit</md-icon>
<!-- from -->
<sg-avatar-image 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">
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-button class="sg-icon-button" ng-click="editor.send()"
ng-disabled="!(editor.message.editable.to.length > 0 || editor.message.editable.cc.length > 0 || editor.message.editable.bcc.length > 0)">
<md-icon>send</md-icon>
</md-button>
<md-button class="sg-icon-button " ng-click="editor.message.$save()">
<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-button class="sg-icon-button" ng-click="editor.cancel()">
<md-icon>close</md-icon>
</md-button>
</div>
</div>
</md-toolbar>
<md-dialog-content>
<header>
<!-- TO / CC/ BCC / SUBJECT / ATTACHMENTS -->
<div class="msg-header-content">
<md-dialog-content class="md-padding">
<header>
<div class="msg-header-content">
<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-autocomplete
md-selected-item="editor.autocomplete.to.selected"
md-search-text="editor.autocomplete.to.searchText"
md-items="user in editor.contactFilter(editor.autocomplete.to.searchText)"
label:placeholder="Add a recipient">
<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>
<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-autocomplete
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">
<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>
<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-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">
<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>
<md-input-container>
<label>
<var:string label:value="Subject"/>
</label>
<input type="text" name="subject" ng-model="editor.message.editable.subject"/>
</md-input-container>
<!-- to -->
<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-transform-chip="editor.addRecipient($chip)">
<md-autocomplete
class="sg-chips-autocomplete"
md-autofocus="true"
md-search-text="editor.autocomplete.to.searchText"
md-selected-item="editor.autocomplete.to.selected"
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>
</md-autocomplete>
<md-chip-template>{{$chip}}</md-chip-template>
</md-chips>
</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>
<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>
<!-- 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-transform-chip="editor.addRecipient($chip)">
<md-autocomplete
class="sg-chips-autocomplete"
md-search-text="editor.autocomplete.cc.searchText"
md-selected-item="editor.autocomplete.cc.selected"
md-items="user in editor.contactFilter(editor.autocomplete.cc.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>
</md-autocomplete>
<md-chip-template>{{$chip}}</md-chip-template>
</md-chips>
</div>
</header>
<!-- MESSAGE CONTENT -->
<textarea name="content" var:class="editorClass"
ck-locale="editor.localeCode"
ng-model="editor.message.editable.text"/>
<!-- 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-transform-chip="editor.addRecipient($chip)">
<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)"
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>
</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>
</div>
<!-- toolbar to show cc/bcc/attachment fields -->
<div layout="column" layout-align="end 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">
<md-dialog-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>
<!-- Attachments -->
<md-chips ng-model="editor.uploader.queue"
class="md-flex sg-readonly" readonly="true">
<md-chip-template>
<span class="sg-chip-progress" ng-show="$chip.isUploading">
<span class="md-default-theme md-warn md-bg"
ng-style="{ width: $chip.progress + '%'}"><!-- progress --></span>
</span>
<a ng-href="{{$chip.inlineUrl}}" target="_new">{{$chip.file.name}}</a>
<md-icon ng-class="{ 'md-warn': $chip.isUploading }"
ng-click="editor.removeAttachment($chip)">close</md-icon>
</md-chip-template>
</md-chips>
<label class="md-button md-icon-button" for="file-input">
<md-icon>attach_file</md-icon>
<!-- <span><var:string label:value="Attach"/></span> -->
</label>
<input id="file-input" type="file"
<input id="file-input" name="file-input" type="file" class="ng-hide"
nv-file-select="nv-file-select"
multiple="multiple"
uploader="editor.uploader"
ng-show="false"/>
</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>
uploader="editor.uploader"/>
<!--
Disable multiple until this issue is resolved:
https://github.com/nervgh/angular-file-upload/issues/525
-->
<!-- multiple="multiple" -->
</div>
</div>
</div>
</md-dialog>
</md-dialog-actions>
</md-dialog>
</container>
+259 -38
View File
@@ -4,49 +4,262 @@
xmlns:var="http://www.skyrix.com/od/binding"
xmlns:label="OGo:label">
<div class="view-list" layout="column">
<!-- in virtual mailbox mode -->
<md-toolbar class="md-whiteframe-z1"
ng-hide="!app.showingAdvancedSearch || mailbox.selectedFolder.$selectedCount() > 0">
<div class="md-toolbar-tools">
<md-input-container>
<label><var:string label:value="Search messages in"/></label>
<md-select ng-model="app.search.mailbox">
<md-option ng-value="">
<span>{{app.accounts[0].name}}</span>
</md-option>
<md-option ng-repeat="folder in
app.accounts[0].$flattenMailboxes()
track by folder.path"
ng-value="folder.path">
<span ng-class="'sg-child-level-' + folder.level">{{folder.name}}</span>
</md-option>
</md-select>
</md-input-container>
<md-menu>
<md-button class="sg-icon-button" label:aria-label="More search options" ng-click="$mdOpenMenu()">
<md-icon>settings</md-icon>
</md-button>
<md-menu-content>
<md-menu-item>
<md-button ng-href="#">
<md-checkbox ng-model="app.search.subfolders"
ng-true-value="1"
ng-false-value="0">
<var:string label:value="Search subfolders"/>
</md-checkbox>
</md-button>
</md-menu-item>
<md-menu-item>
<md-button ng-click="app.search.match='AND'">
<md-icon ng-class="{ 'icon-check': app.search.match == 'AND'}">
<!-- all --></md-icon><var:string label:value="Match all of the following"/>
</md-button>
</md-menu-item>
<md-menu-item>
<md-button ng-click="app.search.match='OR'">
<md-icon ng-class="{ 'icon-check': app.search.match == 'OR'}">
<!-- any --></md-icon><var:string label:value="Match any of the following"/>
</md-button>
</md-menu-item>
</md-menu-content>
</md-menu>
<md-button class="sg-icon-button"
ng-click="app.toggleAdvancedSearch()"
ng-disabled="app.search.params.length == 0">
<md-icon ng-class="{'icon-stop': app.service.selectedFolder.$isLoading,
'icon-search': !app.service.selectedFolder.$isLoading}"><!-- icon --></md-icon>
</md-button>
</div>
</md-toolbar>
<!-- single-selection toolbars -->
<md-toolbar class="md-whiteframe-z1"
ng-hide="app.showingAdvancedSearch || mailbox.selectedFolder.$selectedCount() > 0">
<!-- sort mode (default) -->
<div class="md-toolbar-tools" ng-hide="mailbox.mode.search">
<md-button class="sg-icon-button" label:aria-label="Search"
ng-click="mailbox.mode.search = true">
<md-icon>search</md-icon>
</md-button>
<div class="sg-folder-name">{{mailbox.selectedFolder.name}}</div>
<md-menu>
<md-button class="sg-icon-button" label:aria-label="Sort"
ng-click="$mdOpenMenu()">
<md-icon>sort</md-icon>
</md-button>
<md-menu-content>
<md-menu-item>
<md-button ng-click="mailbox.sort('subject')">
<md-icon ng-class="{ 'icon-check': mailbox.sortedBy('subject') }">
<!-- subject --></md-icon> <var:string label:value="Subject"/>
</md-button>
</md-menu-item>
<md-menu-item>
<md-button ng-click="mailbox.sort('from')">
<md-icon ng-class="{ 'icon-check': mailbox.sortedBy('from') }">
<!-- from --></md-icon> <var:string label:value="From"/>
</md-button>
</md-menu-item>
<md-menu-item>
<md-button ng-click="mailbox.sort('date')">
<md-icon ng-class="{ 'icon-check': mailbox.sortedBy('date') }">
<!-- date --></md-icon> <var:string label:value="Date"/>
</md-button>
</md-menu-item>
<md-menu-item>
<md-button ng-click="mailbox.sort('size')">
<md-icon ng-class="{ 'icon-check': mailbox.sortedBy('size') }">
<!-- size --></md-icon> <var:string label:value="Size"/>
</md-button>
</md-menu-item>
<md-menu-divider> <!-- divider --></md-menu-divider>
<md-menu-item>
<md-button ng-click="mailbox.selectedFolder.$filter()">
<md-checkbox
ng-model="mailbox.service.$query.asc"
ng-true-value="0"
ng-false-value="1"><var:string label:value="Descending Order"/></md-checkbox>
</md-button>
</md-menu-item>
</md-menu-content>
</md-menu>
<md-button class="sg-icon-button" aria-label="Refresh" ng-click="mailbox.selectedFolder.$filter()" >
<md-icon>refresh</md-icon>
</md-button>
</div>
<!-- search mode -->
<div class="md-toolbar-tools sg-toolbar-secondary"
ng-show="mailbox.mode.search"
sg-search="mailbox.selectedFolder.$filter({ sort: 'date', asc: false }, [{ searchBy: searchField, searchInput: searchText }])">
<md-button class="sg-icon-button"
sg-search-cancel="mailbox.cancelSearch()"
label:aria-label="Back">
<md-icon>arrow_back</md-icon>
</md-button>
<md-input-container md-no-float="md-no-float">
<input name="folderSearch" type="search" ng-minlength="3" label:placeholder="Search"/>
</md-input-container>
<md-input-container flex="25">
<md-select>
<md-option value="subject" selected="selected"><var:string label:value="Subject"/></md-option>
<md-option value="from"><var:string label:value="Sender"/></md-option>
<md-option value="subject_or_from"><var:string label:value="Subject or Sender"/></md-option>
<md-option value="to_or_cc"><var:string label:value="To or Cc"/></md-option>
<md-option value="body"><var:string label:value="Entire Message"/></md-option>
</md-select>
</md-input-container>
</div>
</md-toolbar>
<!-- multiple-selection mode -->
<md-toolbar class="md-hue-1 sg-toolbar-secondary" ng-show="mailbox.selectedFolder.$selectedCount() > 0">
<div class="md-toolbar-tools">
<md-button class="sg-icon-button" ng-click="mailbox.unselectMessages()">
<md-icon>arrow_back</md-icon>
</md-button>
<label>{{mailbox.service.selectedFolder.$selectedCount()}} <var:string label:value="selected"/></label>
<div class="md-flex"><!-- spacer --></div>
<md-button class="sg-icon-button" ng-click="mailbox.selectAll()">
<md-tooltip md-direction="bottom"><var:string label:value="Select All"/></md-tooltip>
<md-icon>select_all</md-icon>
</md-button>
<md-button class="sg-icon-button" ng-click="mailbox.confirmDeleteSelectedMessages()">
<md-icon>delete</md-icon>
</md-button>
<md-menu>
<md-button class="sg-icon-button" label:aria-label="Copy messages" ng-click="$mdOpenMenu()">
<md-tooltip md-direction="bottom"><var:string label:value="Copy To"/></md-tooltip>
<md-icon>content_copy</md-icon>
</md-button>
<md-menu-content width="4">
<div ng-repeat="account in mailbox.accounts track by account.id">
<md-menu-item>
<md-button class="md-primary" ng-disabled="true">{{account.name}}</md-button>
</md-menu-item>
<md-menu-divider><!-- divider --></md-menu-divider>
<md-menu-item ng-repeat="folder in
account.$flattenMailboxes()
track by folder.path"
ng-hide="mailbox.id == folder.id">
<md-button ng-click="mailbox.copySelectedMessages(folder.id)">
<span ng-class="'sg-child-level-' + folder.level">{{folder.name}}</span>
</md-button>
</md-menu-item>
</div>
</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="mailbox.markSelectedMessagesAsFlagged()">
<var:string label:value="Flag"/>
</md-button>
</md-menu-item>
<md-menu-item>
<md-button ng-click="mailbox.markSelectedMessagesAsUnread()">
<var:string label:value="Mark as Unread"/>
</md-button>
</md-menu-item>
<md-menu-item>
<md-button ng-click="mailbox.saveSelectedMessages()">
<var:string label:value="Save As..."/>
</md-button>
</md-menu-item>
</md-menu-content>
</md-menu>
</div>
</md-toolbar>
<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>
<span ng-show="mailbox.selectedFolder.$messages.length == 0"><var:string label:value="No message"/></span>
</h2>
</header>
<md-subheader>
<!-- toggle sidenav -->
<md-button class="md-icon-button hide show-gt-sm" ng-click="toggleLeft()">
<md-icon ng-class="{'md-rotate-180': leftIsClose }">keyboard_arrow_left</md-icon>
</md-button>
<!-- message count -->
<span ng-switch="mailbox.service.selectedFolder.getLength()">
<span ng-switch-when="0"><var:string label:value="No message"/></span>
<span ng-switch-default="true">{{mailbox.service.selectedFolder.getLength()}} <var:string label:value="messages"/></span>
</span>
</md-subheader>
<md-virtual-repeat-container class="md-flex">
<md-list class="sg-section-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>
<md-list-item
class="md-default-theme md-background md-hue-1"
md-virtual-repeat="currentMessage in mailbox.service.selectedFolder"
md-on-demand="md-on-demand"
ng-class="{'md-bg': mailbox.selectedFolder.isSelectedMessage(currentMessage.uid, currentMessage.$mailbox.path),
unread: !currentMessage.isread}"
ng-click="mailbox.selectMessage(currentMessage)">
<sg-avatar-image class="md-avatar"
ng-if="!currentMessage.selected"
ng-click="mailbox.toggleMessageSelection($event, currentMessage)"
sg-email="::currentMessage.from[0].email"
size="40"><!-- avatar --></sg-avatar-image>
<div class="md-avatar sg-avatar-selected"
ng-if="currentMessage.selected"
ng-click="mailbox.toggleMessageSelection($event, currentMessage)"><!-- selected avatar --></div>
<div class="sg-tile-content">
<div class="sg-md-subhead">
<div>
<span class="sg-label-outline"
ng-show="mailbox.service.$virtualMode">{{currentMessage.$mailbox.name}}</span>
<md-icon ng-show="currentMessage.priority.level == 1 ||
currentMessage.priority.level == 2"
ng-class="{'md-warn': currentMessage.priority.level == 1}">error</md-icon>
{{currentMessage.$shortAddress('from')}}
</div>
<div class="sg-tile-date" ng-bind="currentMessage.relativedate"><!-- date --></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 class="sg-md-body">
<div>{{currentMessage.subject}}</div>
</div>
</md-list-item>
</div>
</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>
</md-list>
</md-virtual-repeat-container>
<div class="sg-progress-circular-floating"
ng-show="mailbox.service.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)">
@@ -55,7 +268,15 @@
</md-content>
</div>
<div id="detailView" class="view-detail ng-cloak" layout="column" ui-view="message"
ng-show="mailbox.selectedFolder.selectedMessage"><!-- message view --></div>
<div id="detailView" class="view-detail md-default-theme md-background md-bg md-hue-1"
layout="column" layout-align="start center"
ng-class="{ 'sg-close': !mailbox.service.selectedFolder.selectedMessage }"
ui-view="message">
<md-toolbar class="md-whiteframe-z1 hide-sm"><!-- empty toolbar --></md-toolbar>
<md-content class="hide-sm md-flex layout-fill md-hue-1"
layout="column" layout-align="center center">
<div class="md-default-theme md-background md-fg md-hue-3 sg-md-title"><var:string label:value="No message selected"/></div>
</md-content>
</div>
</container>
+87 -167
View File
@@ -8,11 +8,11 @@
xmlns:label="OGo:label"
className="UIxPageFrame"
title="title"
const:jsFiles="Common.js, Contacts.services.js, Mailer.services.js, Preferences.services.js, Mailer.js, Mailer.services.js, vendor/ckeditor/ckeditor.js, vendor/ckeditor/ck.js, vendor/angular-file-upload.min.js">
const:jsFiles="Common.js, Preferences.services.js, Contacts.services.js, Mailer.js, Mailer.services.js, vendor/ckeditor/ckeditor.js, vendor/ckeditor/ck.js, vendor/angular-file-upload.min.js">
<script type="text/javascript">
var mailAccounts =<var:string value="mailAccounts" const:escapeHTML="NO" />;
var userNames =<var:string value="userNames" const:escapeHTML="NO" />;
var unseenCountFolders =<var:string value="unseenCountFolders" const:escapeHTML="NO" />;
var mailAccounts = <var:string value="mailAccounts" const:escapeHTML="NO" />;
var userNames = <var:string value="userNames" const:escapeHTML="NO" />;
var unseenCountFolders = <var:string value="unseenCountFolders" const:escapeHTML="NO" />;
</script>
<style type="text/css">
<var:foreach list="availableLabels" item="currentLabel">
@@ -223,30 +223,30 @@
-->
<main class="view 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 class="md-sidenav-left md-whiteframe-z1 layout-fill" layout="column"
md-component-id="left" md-is-locked-open="isGtMedium"
ng-class="{ 'sg-closed': leftIsClose }">
<var:component className="UIxSidenavToolbarTemplate" />
<md-content md-scroll-y="md-scroll-y" class="md-flex">
<md-content md-scroll-y="md-scroll-y" class="md-flex md-hue-2">
<section ng-repeat="account in app.accounts track by account.id">
<md-subheader class="sg-md-subheader">
<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>
</div>
<md-subheader class="md-hue-2">
<div layout="row" layout-align="start center">
<div class="sg-no-wrap">{{account.name}}</div>
<div class="md-flex"><!-- spacer --></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>
</div>
</md-subheader>
<md-list>
@@ -254,16 +254,23 @@
ng-click="app.selectFolder(account, folder)"
ng-dblclick="app.editFolder(folder)"
ui-sref="mail.account.mailbox({accountId: account.id, mailboxId: (folder.path | encodeUri)})"
ui-sref-active="sg-active">
<md-icon ng-class="'sg-child-level-' + folder.level">{{app.metadataForFolder(folder).icon}}</md-icon>
ui-sref-active="md-default-theme md-background md-bg md-hue-1">
<div ng-class="'sg-child-level-' + folder.level">
<md-icon ng-hide="folder.children.length">{{app.metadataForFolder(folder).icon}}</md-icon>
<md-checkbox class="sg-folder"
label:aria-label="Expanded"
ng-show="folder.children.length"
ng-model="folder.$expanded"
ng-change="account.$flattenMailboxes({ reload: true, saveState: true })"><!-- expanded --></md-checkbox>
</div>
<p class="sg-item-name"
ng-show="app.editMode != folder.path">
{{app.metadataForFolder(folder).name}}
<span ng-show="folder.unseenCount"> ({{folder.unseenCount}})</span>
<span class="sg-counter-badge" ng-show="folder.unseenCount">{{folder.unseenCount}}</span>
</p>
<md-input-container class="md-flex md-tile-content"
<md-input-container class="md-flex"
ng-show="app.editMode == folder.path">
<input class="folder-name" type="text"
<input class="sg-item-name" type="text"
label:aria-label="Enter the new name of your folder"
ng-model="folder.name"
ng-blur="app.saveFolder(folder)"
@@ -312,6 +319,12 @@
<var:string label:value="Export"/>
</md-button>
</md-menu-item>
<md-menu-item>
<md-button type="button"
ng-click="app.showAdvancedSearch(folder.path)">
<var:string label:value="Search"/>
</md-button>
</md-menu-item>
<md-menu-divider ng-show="folder.type == 'folder'"><!-- divider --></md-menu-divider>
<md-menu-item ng-show="folder.type == 'folder'">
<md-button type="button" ng-click="app.setFolderAs(folder, 'Drafts')">
@@ -346,151 +359,58 @@
</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 sg-padded"
layout="row" layout-align="space-between start">
<var:component className="UIxTopnavToolbarTemplate" />
<md-toolbar layout="row" layout-align="space-between center" class="toolbar-main"
ng-hide="app.showingAdvancedSearch">
<var:component className="UIxTopnavToolbarTemplate"/>
</md-toolbar>
<!-- Advanced search toolbar -->
<md-toolbar layout="column" class="md-tall toolbar-main"
ng-show="app.showingAdvancedSearch">
<div class="md-toolbar-tools">
<md-chips class="md-flex"
ng-model="app.search.params"
md-on-append="app.newSearchParam($chip)">
<input sg-focus-on="advancedSearch" type="text"
ng-disabled="app.currentSearchParam.length == 0"
sg-placeholder="app.search.options[app.currentSearchParam]"/>
<md-chip-template>
<span class="md-caption" ng-show="$chip.negative == 0">(match</span>
<span class="md-caption" ng-show="$chip.negative == 1">(does not match</span>
<span class="md-caption">{{$chip.searchBy}})</span>
<span>{{$chip.searchInput}}</span>
</md-chip-template>
</md-chips>
<md-button type="button" class="sg-icon-button" ng-click="app.hideAdvancedSearch()">
<md-icon>close</md-icon>
</md-button>
</div>
<div class="md-toolbar-tools" layout="row" layout-align="space-between center"
ng-show="mailbox.selectedFolder.$selectedCount() == 0">
<!-- sort mode -->
<div class="view-list" layout="row" layout-align="space-between center"
ng-hide="mailbox.mode.search">
<div class="sg-toolbar-group">
<md-button class="sg-icon-button" label:aria-label="Search"
ng-click="mailbox.mode.search = true">
<md-icon>search</md-icon>
</md-button>
<div class="md-toolbar-tools">
<div layout="column">
<div class="pseudo-input-container--compact">
<label class="pseudo-input-label"><var:string label:value="Add a Criteria"/></label>
</div>
<div class="sg-toolbar-group-last">
<md-menu>
<md-button class="sg-icon-button" label:aria-label="Sort"
ng-click="$mdOpenMenu()">
<md-icon>sort</md-icon>
</md-button>
<md-menu-content>
<md-menu-item>
<md-button ng-click="mailbox.sort('subject')">
<md-icon ng-class="{ 'icon-check': mailbox.sortedBy('subject') }">
<!-- subject --></md-icon> <var:string label:value="Subject"/>
</md-button>
</md-menu-item>
<md-menu-item>
<md-button ng-click="mailbox.sort('from')">
<md-icon ng-class="{ 'icon-check': mailbox.sortedBy('from') }">
<!-- from --></md-icon> <var:string label:value="From"/>
</md-button>
</md-menu-item>
<md-menu-item>
<md-button ng-click="mailbox.sort('date')">
<md-icon ng-class="{ 'icon-check': mailbox.sortedBy('date') }">
<!-- date --></md-icon> <var:string label:value="Date"/>
</md-button>
</md-menu-item>
<md-menu-item>
<md-button ng-click="mailbox.sort('size')">
<md-icon ng-class="{ 'icon-check': mailbox.sortedBy('size') }">
<!-- size --></md-icon> <var:string label:value="Size"/>
</md-button>
</md-menu-item>
<md-menu-divider> <!-- divider --></md-menu-divider>
<md-menu-item>
<md-button ng-click="mailbox.selectedFolder.$filter()">
<md-checkbox
ng-model="mailbox.service.$query.asc"
ng-true-value="0"
ng-false-value="1"><var:string label:value="Descending Order"/></md-checkbox>
</md-button>
</md-menu-item>
</md-menu-content>
</md-menu>
<md-button class="sg-icon-button" aria-label="Refresh" ng-click="mailbox.selectedFolder.$filter()" >
<md-icon>refresh</md-icon>
</md-button>
<div layout="row">
<span class="md-button sg-outline-button" ng-click="app.addSearchParam('subject')">
<var:string label:value="Subject"/>
</span>
<span class="md-button sg-outline-button" ng-click="app.addSearchParam('from')">
<var:string label:value="From"/>
</span>
<span class="md-button sg-outline-button" ng-click="app.addSearchParam('to')">
<var:string label:value="To"/>
</span>
<span class="md-button sg-outline-button" ng-click="app.addSearchParam('cc')">
<var:string label:value="Cc"/>
</span>
<span class="md-button sg-outline-button" ng-click="app.addSearchParam('body')">
<var:string label:value="Body"/>
</span>
</div>
</div>
<!-- search mode -->
<div class="view-list sg-padded--right sg-toolbar-search" layout="row" layout-align="space-between center"
ng-show="mailbox.mode.search"
sg-search="mailbox.selectedFolder.$filter({ sort: 'date', asc: false }, [{ searchBy: searchField, searchInput: searchText }])">
<md-button class="sg-icon-button"
sg-search-cancel="mailbox.cancelSearch()"
label:aria-label="Back">
<md-icon>arrow_back</md-icon>
</md-button>
<md-input-container>
<input name="folderSearch" type="search" />
</md-input-container>
<md-input-container>
<md-select>
<md-option value="subject" selected="selected"><var:string label:value="Subject"/></md-option>
<md-option value="from"><var:string label:value="Sender"/></md-option>
<md-option value="subject_or_from"><var:string label:value="Subject or Sender"/></md-option>
<md-option value="to_or_cc"><var:string label:value="To or Cc"/></md-option>
<md-option value="body"><var:string label:value="Entire Message"/></md-option>
</md-select>
</md-input-container>
</div>
</div>
<div layout="row" layout-align="start center" ng-show="mailbox.selectedFolder.$selectedCount() > 0">
<md-button class="sg-icon-button" ng-click="mailbox.unselectMessages()">
<md-icon>arrow_back</md-icon>
</md-button>
<label>{{mailbox.selectedFolder.$selectedCount()}} selected</label>
<md-button class="sg-icon-button" ng-click="mailbox.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="mailbox.confirmDeleteSelectedMessages()">
<md-icon>delete</md-icon>
</md-button>
<md-menu>
<md-button class="sg-icon-button" label:aria-label="Copy messages" 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">
<div ng-repeat="account in mailbox.accounts track by account.id">
<md-menu-item>
<md-button class="md-primary" ng-disabled="true">{{account.name}}</md-button>
</md-menu-item>
<md-menu-divider><!-- divider --></md-menu-divider>
<md-menu-item ng-repeat="folder in
account.$flattenMailboxes()
track by folder.path"
ng-hide="mailbox.id == folder.id">
<md-button ng-click="mailbox.copySelectedMessages(folder.id)">
<span ng-class="'sg-child-level-' + folder.level">{{folder.name}}</span>
</md-button>
</md-menu-item>
</div>
</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="mailbox.markSelectedMessagesAsFlagged()">
<var:string label:value="Flag"/>
</md-button>
</md-menu-item>
<md-menu-item>
<md-button ng-click="mailbox.markSelectedMessagesAsUnread()">
<var:string label:value="Mark as Unread"/>
</md-button>
</md-menu-item>
<md-menu-item>
<md-button ng-click="mailbox.saveSelectedMessages()">
<var:string label:value="Save As..."/>
</md-button>
</md-menu-item>
</md-menu-content>
</md-menu>
</div>
</md-toolbar>
<div layout="row" class="md-flex">
<var:component className="UIxMailFolderTemplate" />
</div>
+24 -21
View File
@@ -1,29 +1,32 @@
<?xml version="1.0" standalone="yes"?>
<var:component xmlns="http://www.w3.org/1999/xhtml"
<!DOCTYPE var:component>
<var:component
xmlns="http://www.w3.org/1999/xhtml"
xmlns:var="http://www.skyrix.com/od/binding"
xmlns:const="http://www.skyrix.com/od/constant"
xmlns:uix="OGo:uix"
xmlns:label="OGo:label"
className="UIxPageFrame"
title="title"
const:jsFiles="SOGoAutoCompletion.js"
const:userDefaultsKeys="SOGoMailDisplayRemoteInlineImages"
const:popup="YES">
<script type="text/javascript">
var messageName = '<var:string value="clientObject.relativeImap4Name"/>';
var mailboxName = '/<var:string value="clientObject.container.container.nameInContainer"/>/<var:string value="clientObject.container.nameInContainer"/>';
</script>
<var:component className="UIxMailView" />
<div class="menu" id="addressMenu">
<ul>
<li id="add_to_addressbook"><var:string label:value="Add to Address Book..."/></li>
<li id="compose_mailto"><var:string label:value="Compose Mail To"/></li>
<li id="create_filter"><var:string label:value="Create Filter From Message..."/></li>
</ul>
const:popup="YES"
const:jsFiles="Common.js, Contacts.services.js, Preferences.services.js, Mailer.app.popup.js, Mailer.services.js, vendor/ckeditor/ckeditor.js, vendor/ckeditor/ck.js, vendor/angular-file-upload.min.js">
<main class="layout-fill" ng-controller="navController">
<div id="detailView" class="view-detail" layout="column" layout-align="start center"
ui-view="message">
<div class="sg-progress-circular-floating">
<md-progress-circular class="md-accent ng-cloak"
md-mode="indeterminate"
md-diameter="32"><!-- progress --></md-progress-circular>
</div>
</div>
<div class="menu" id="imageMenu">
<ul>
<li id="save_image"><var:string label:value="Save Image"/></li>
</ul>
</div>
</var:component>
</main>
<script type="text/ng-template" id="UIxMailViewTemplate">
<var:component className="UIxMailViewTemplate" />
</script>
<script type="text/ng-template" id="UIxMailEditor">
<var:component className="UIxMailEditor" />
</script>
</var:component>
@@ -7,7 +7,7 @@
xmlns:label="OGo:label"
>
<md-dialog flex="30" flex-sm="100">
<md-toolbar class="sg-padded">
<md-toolbar>
<div class="md-toolbar-tools">
<md-icon class="material-icons sg-icon-toolbar-bg">folder_shared</md-icon>
<div class="pseudo-input-container md-flex">
@@ -20,16 +20,38 @@
</div>
</md-toolbar>
<md-dialog-content>
<md-dialog-content class="md-padding">
<div>
<md-autocomplete
class="md-flex"
md-input-name="addUser"
md-search-text="delegate.searchText"
md-selected-item="delegate.userToAdd"
md-selected-item-change="delegate.addUser(user)"
md-items="user in delegate.userFilter(delegate.searchText)"
md-item-text="user.empty"
md-min-length="3"
md-no-cache="true"
label:md-floating-label="Add User">
<span class="md-contact-suggestion" layout="row" layout-align="space-between center">
<span class="md-contact-name"
md-highlight-text="delegate.searchText"
md-highlight-flags="^i">{{user.cn}}</span> <span class="md-contact-email"
md-highlight-text="delegate.searchText"
md-highlight-flags="^i">{{user.c_email}}</span>
</span>
</md-autocomplete>
</div>
<md-list>
<md-list-item ng-repeat="user in delegate.users | orderBy:['userClass', 'displayName']">
<div layout="row" layout-align="start center" class="md-flex">
<sg-avatar-image class="md-tile-left"
<div layout="row" layout-align="start center" class="md-flex card-picture">
<sg-avatar-image class="md-avatar"
sg-email="user.c_email"
size="48"><!-- avatar --></sg-avatar-image>
size="40"><!-- avatar --></sg-avatar-image>
<div class="sg-tile-content">
<div class="sg-md-subhead-multi">{{user.cn}}</div>
<div class="sg-md-body-multi">{{user.c_email}}</div>
<div class="sg-md-subhead"><div>{{user.cn}}</div></div>
<div class="sg-md-body"><div>{{user.c_email}}</div></div>
</div>
<md-button class="sg-icon-button" ng-click="delegate.removeUser(user)">
<md-icon>delete</md-icon>
@@ -38,27 +60,5 @@
</md-list-item>
</md-list>
</md-dialog-content>
<div class="md-actions">
<md-autocomplete
class="md-flex"
md-input-name="addUser"
md-search-text="delegate.searchText"
md-selected-item="delegate.userToAdd"
md-selected-item-change="delegate.addUser(user)"
md-items="user in delegate.userFilter(delegate.searchText)"
md-item-text="user.empty"
md-min-length="3"
md-no-cache="true"
label:md-floating-label="Add User">
<span class="md-contact-suggestion" layout="row" layout-align="space-between center">
<span class="md-contact-name"
md-highlight-text="delegate.searchText"
md-highlight-flags="^i">{{user.cn}}</span> <span class="md-contact-email"
md-highlight-text="delegate.searchText"
md-highlight-flags="^i">{{user.c_email}}</span>
</span>
</md-autocomplete>
</div>
</md-dialog>
</container>
+165 -130
View File
@@ -1,105 +1,51 @@
<?xml version='1.0' standalone='yes'?>
<container
xmlns="http://www.w3.org/1999/xhtml"
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:uix="OGo:uix">
xmlns="http://www.w3.org/1999/xhtml"
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:uix="OGo:uix">
<md-content md-scroll-y="md-scroll-y" class="viewer md-padding md-flex bg-sogoPaper-50 md-whiteframe-z1">
<header class="msg-header">
<div class="msg-header-content">
<div layout="row" layout-align="start center">
<md-button class="sg-icon-button sg-msg-flag" label:aria-label="flagged" ng-click="viewer.message.toggleFlag()">
<md-icon ng-class="{'flagged': viewer.message.isflagged}">star</md-icon>
</md-button>
<h3 class="sg-md-title-msg" ng-bind="viewer.message.subject"><!-- subject --></h3>
</div>
<div class="pseudo-input-container--compact">
<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>
</div>
<div class="pseudo-input-container--compact">
<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>
</div>
</div>
<md-chips class="sg-readonly" ng-model="viewer.message.flags" ng-change="viewer.changeFlags()">
<md-chip-template>{{viewer.service.$tags[$chip][0]}}</md-chip-template>
<md-autocomplete
md-selected-item="viewer.tags.selected"
md-selected-item-change="viewer.message.addTag(viewer.tags.selected)"
md-search-text="viewer.tags.searchText"
md-items="tag in viewer.service.filterTags(viewer.tags.searchText)"
label:placeholder="Add a tag">
<span md-highlight-text="viewer.tags.searchText">{{viewer.service.$tags[tag][0]}}</span>
</md-autocomplete>
</md-chips>
</div>
<!-- <p class="flags">
&lt;!&ndash; Todo: change the text for an icon (conditional ?) The read/unread flag doesn't make sense at his place&ndash;&gt;
<span class="pseudo-input-label" ng-repeat="flag in message.flags">{{flag}}</span>
</p>
-->
<div class="sg-icon-bar--vertical">
<md-button class="sg-icon-button show-sm"
<div layout="column" class="layout-fill">
<md-toolbar>
<div class="md-toolbar-tools">
<md-button class="sg-icon-button"
ng-if="isPopup"
label:aria-label="Close"
ng-click="toggleDetailView()">
ng-click="viewer.closePopup()">
<md-icon>close</md-icon>
</md-button>
<!-- todo: Replace md-tooltip values by localizable string variable -->
<md-button class="sg-icon-button hide show-sm"
ng-hide="isPopup"
label:aria-label="Close"
ng-click="viewer.close()">
<md-icon>arrow_back</md-icon>
</md-button>
<div class="md-flex hide show-sm"><!-- spacer --></div>
<md-button class="sg-icon-button" label:aria-label="flagged" ng-click="viewer.message.toggleFlag()">
<md-icon ng-class="{'icon-star': viewer.message.isflagged,
'icon-star-border': !viewer.message.isflagged}"><!-- flag --></md-icon>
</md-button>
<div class="md-flex hide-sm"><!-- spacer --></div>
<md-button class="sg-icon-button"
ng-hide="viewer.message.isDraft"
ng-click="viewer.reply($event)"
label:aria-label="reply">
<md-tooltip md-direction="left"><var:string label:value="Reply to Sender Only"/></md-tooltip>
label:aria-label="Reply">
<md-tooltip md-direction="bottom"><var:string label:value="Reply to Sender Only"/></md-tooltip>
<md-icon>reply</md-icon>
</md-button>
<md-button class="sg-icon-button"
ng-show="viewer.message.allowReplyAll()"
ng-click="viewer.replyAll($event)"
label:aria-label="Reply All">
<md-tooltip md-direction="bottom"><var:string label:value="Reply to sender and all recipients"/></md-tooltip>
<md-icon>reply_all</md-icon>
</md-button>
<md-button class="sg-icon-button" label:aria-label="Forward"
ng-hide="viewer.message.isDraft"
ng-click="viewer.forward($event)">
<md-tooltip md-direction="left"><var:string label:value="Forward selected message"/></md-tooltip>
<md-tooltip md-direction="bottom"><var:string label:value="Forward selected message"/></md-tooltip>
<md-icon>forward</md-icon>
</md-button>
<md-button class="sg-icon-button" label:aria-label="Edit"
@@ -109,25 +55,24 @@
</md-button>
<md-button class="sg-icon-button" label:aria-label="Delete"
ng-click="viewer.doDelete()">
<md-tooltip md-direction="left"><var:string label:value="Delete selected message or folder"/></md-tooltip>
<md-tooltip md-direction="bottom"><var:string label:value="Delete selected message or folder"/></md-tooltip>
<md-icon>delete</md-icon>
</md-button>
<md-button class="sg-icon-button hide-sm" label:aria-label="Open in New Mail Window"
ng-hide="isPopup"
ng-click="viewer.openPopup()">
<md-tooltip md-direction="bottom"><var:string label:value="Open in New Mail Window"/></md-tooltip>
<md-icon>open_in_new</md-icon>
</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 ng-hide="viewer.message.isDraft">
<md-button label:aria-label="Reply All"
ng-click="viewer.replyAll($event)">
<var:string label:value="Reply All"/>
</md-button>
</md-menu-item>
<md-menu-item ng-show="viewer.message.$hasUnsafeContent">
<md-button label:aria-label="Load Images"
ng-click="viewer.message.loadUnsafeContent()">
<var:string label:value="Load Images"/>
<md-menu-item ng-hide="viewer.showFlags">
<md-button label:aria-label="Add a tag"
ng-click="viewer.showFlags = true">
<var:string label:value="Add a tag"/>
</md-button>
</md-menu-item>
<md-menu-item>
@@ -144,38 +89,128 @@
</md-menu-item>
</md-menu-content>
</md-menu>
</div>
</header>
<md-divider><!-- divider --></md-divider>
</md-toolbar>
<md-content class="md-flex md-static">
<div class="viewer">
<md-toolbar class="sg-padded">
<h3 class="sg-md-title-msg">{{viewer.message.subject}}</h3>
<time class="msg-date" datetime="viewer.message.date" ng-bind="viewer.message.date"><!-- date --></time>
</md-toolbar>
<md-toolbar class="sg-padded">
<div ng-show="viewer.message.shouldAskReceipt == 1"
layout-padding="layout-padding">
<md-whiteframe class="md-whiteframe-z2" layout="column"
layout-align="center start">
<md-icon>warning</md-icon>
<span><var:string label:value="The sender of this message has asked to be notified when you read this message. Do you with to notify the sender?"/></span>
<div class="md-actions" layout="row">
<md-button label:aria-label="Yes"
type="button" class="md-primary"
ng-click="viewer.message.$sendMDN()"><var:string label:value="Yes"/></md-button>
<md-button label:aria-label="No"
type="button"
ng-click="viewer.message.shouldAskReceipt = 0"><var:string label:value="No"/></md-button>
</div>
</md-whiteframe>
</div>
<div class="pseudo-input-container--compact">
<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="40">
<!-- 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>
</div>
<div class="pseudo-input-container--compact">
<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>
</div>
</div>
<md-chips class="sg-readonly hide-sm"
ng-show="viewer.showFlags"
ng-model="viewer.message.flags"
md-on-append="$chip.name"
md-on-remove="viewer.message.removeTag($chip)">
<md-chip-template>{{viewer.service.$tags[$chip][0]}}</md-chip-template>
<md-autocomplete
md-selected-item="viewer.tags.selected"
md-selected-item-change="viewer.message.addTag(viewer.tags.selected.name)"
md-search-text="viewer.tags.searchText"
md-items="tag in viewer.service.filterTags(viewer.tags.searchText)"
md-autoselect="true"
label:placeholder="Add a tag">
<md-item-template>
<span md-highlight-text="viewer.tags.searchText"
md-highlight-flags="^i">{{tag.description}}</span>
</md-item-template>
</md-autocomplete>
</md-chips>
</md-toolbar>
<md-content md-scroll-x="md-scroll-x" class="md-padding md-whiteframe-z1">
<div class="msg-body">
<div class="msg-date sg-md-body-multi">
<time datetime="viewer.message.date" ng-bind="viewer.message.date"><!-- date --></time>
<!-- Load external images -->
<md-whiteframe class="md-whiteframe-z2" layout="row" layout-align="space-between center"
ng-show="viewer.message.$hasUnsafeContent">
<div layout="row" layout-align="start center" class="layout-fill">
<div class="md-tile-left">
<md-icon>collections</md-icon>
</div>
<p class="hide show-gt-md"><var:string label:value="This message contains external images."/></p>
<div class="md-flex"><!-- spacer --></div>
<md-button label:aria-label="Load Images"
ng-click="viewer.message.loadUnsafeContent()">
<var:string label:value="Load Images"/>
</md-button>
</div>
</md-whiteframe>
<!-- Send MDN -->
<md-whiteframe class="md-whiteframe-z2" layout="column" layout-align="center start"
ng-show="viewer.message.shouldAskReceipt == 1">
<div layout="row" layout-align="start center">
<div class="md-tile-left">
<md-icon>message</md-icon>
</div>
<p class="sg-padded--right"><var:string label:value="The sender of this message has asked to be notified when you read this message. Do you with to notify the sender?"/></p>
</div>
<div class="layout-fill" layout="row" layout-align="end center">
<md-button label:aria-label="No"
type="button"
ng-click="viewer.message.shouldAskReceipt = 0"><var:string label:value="No"/></md-button>
<md-button label:aria-label="Yes"
type="submit"
ng-click="viewer.message.$sendMDN()"><var:string label:value="Yes"/></md-button>
</div>
</md-whiteframe>
<div class="msg-body">
<div layout="row" layout-wrap="layout-wrap">
<div class="mailer_mailcontent" layout="row" layout-wrap="layout-wrap"
ng-repeat="part in viewer.message.$content()"
ng-class="part.msgclass">
<div ng-if="part.html" ng-bind-html="part.content | ensureTarget"><!-- msg --></div>
<div ng-if="part.compile" sg-compile="part.content" sg-zoomable-image="sg-zoomable-image"><!-- msg --></div>
</div>
</div>
</div>
</md-content>
</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>
</div>
</md-content>
</md-content>
</div>
</container>
+21 -17
View File
@@ -15,17 +15,23 @@
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">
<md-content class="md-padding" md-scroll-y="true">
<div class="sg-login" ng-controller="LoginController as app">
<main class="view layout-fill layout-padding md-default-theme md-background md-hue-1 md-bg"
ui-view="login"
layout="row" layout-align="center start"
ng-controller="LoginController as app">
<md-content class="ng-cloak md-whiteframe-z1"
layout="row" layout-align="center center"
layout-xs="column" layout-align-xs="space-between center"
md-scroll-y="true"
ng-show="app.showLogin">
<div id="logo" class="md-padding">
<img const:alt="*" id="splash" rsrc:src="img/sogo-full.svg"/>
</div>
<div class="sg-login md-padding md-default-theme md-bg md-accent layout-fill">
<script type="text/javascript">
var cookieUsername = '<var:string var:value="cookieUsername" const:escapeHTML="NO"/>';
</script>
<div id="login">
<div id="logo">
<img const:alt="*" id="splash" rsrc:src="img/sogo-full.svg"/>
</div>
<form name="loginForm" layout="column"
ng-cloak="ng-cloak"
@@ -44,10 +50,8 @@
<!-- CONNECT BUTTON -->
<div layout="row" layout-align="end center">
<md-button class="md-raised" type="submit" ng-disabled='app.loginForm.$invalid'>
<span>
<var:string label:value="Connect"/>
</span>
<md-button class="md-primary md-hue-1" type="submit" ng-disabled='app.loginForm.$invalid'>
<var:string label:value="Connect"/>
</md-button>
</div>
@@ -84,10 +88,10 @@
</div>
</form>
<div layout="row" layout-align="end end" ng-cloak="ng-cloak">
<md-button class="sg-icon-button fg-sogoPaper-500"
<md-button class="md-icon-button"
label:aria-label="About"
ng-click="app.showAbout()">
<md-icon class="material-icons fg-sogoPaper-500">info</md-icon>
<md-icon class="md-fg">info</md-icon>
</md-button>
</div>
</div>
@@ -96,17 +100,17 @@
</main>
<script type="text/ng-template" id="aboutBox.html">
<md-dialog flex="50">
<md-dialog-content>
<md-dialog flex="50" sm-flex="100">
<md-dialog-content class="md-dialog-content">
<p><a href="http://sogo.nu/" target="_new">sogo.nu</a></p>
<p>Version <var:string value="version"/> (<var:string value="buildDate" />)</p>
<br/>
<p><var:string label:value="AboutBox" const:escapeHTML="NO"/></p>
<!--<img class="full-image" const:alt="Inverse" rsrc:src="img/inverse.png"/>-->
</md-dialog-content>
<div class="md-actions">
<md-dialog-actions>
<md-button ng-click="about.closeDialog()"><var:string label:value="Close"/></md-button>
</div>
</md-dialog-actions>
</md-dialog>
</script>
@@ -10,7 +10,7 @@
className="UIxPageFrame"
>
<md-dialog flex="50" flex-sm="100">
<md-toolbar class="md-padding">
<md-toolbar>
<div class="md-toolbar-tools">
<md-icon class="material-icons sg-icon-toolbar-bg">account_box</md-icon>
<md-input-container>
@@ -24,7 +24,7 @@
</md-button>
</div>
</md-toolbar>
<md-dialog-content>
<md-dialog-content class="md-dialog-content">
<form id="mainForm" name="accountForm" var:href="ownPath">
@@ -136,8 +136,8 @@
</form>
</md-dialog-content>
<div class="md-actions">
<md-dialog-actions>
<md-button ng-disabled="$AccountDialogController.accountForm.$invalid" ng-click="$AccountDialogController.save()"><var:string label:value="Save"/></md-button>
</div>
</md-dialog-actions>
</md-dialog>
</var:component>
+26 -24
View File
@@ -8,20 +8,20 @@
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">
<form name="mainForm" ng-submit="filterEditor.save(mainForm)">
<md-toolbar>
<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"/>
<input class="md-title" type="text" ng-model="filterEditor.filter.name" required="required"/>
</md-input-container>
<md-button type="button" class="sg-icon-button " ng-click="cancel()">
<md-button type="button" class="sg-icon-button " ng-click="filterEditor.cancel()">
<md-icon>close</md-icon>
</md-button>
</div>
</md-toolbar>
<md-dialog-content>
<md-dialog-content class="md-dialog-content">
<script type="text/javascript">
var filterId = '<var:string value="filterId"/>';
var sieveFolderEncoding = '<var:string value="sieveFolderEncoding"/>';
@@ -29,9 +29,9 @@
</script>
<div layout="row" layout-align="start center">
<div><var:string label:value="For incoming messages that"/></div>
<var:string label:value="For incoming messages that"/>
<md-input-container class="md-flex">
<md-select ng-model="filter.match" required="required">
<md-select ng-model="filterEditor.filter.match" required="required">
<md-option const:value="all">
<var:string label:value="match all of the following rules"/>
</md-option>
@@ -49,10 +49,10 @@
<div layout="column">
<div id="filterRules"><!-- empty -->
<md-list>
<md-list-item ng-repeat="rule in filter.rules">
<md-list-item ng-repeat="rule in filterEditor.filter.rules">
<md-input-container flex="25">
<md-select ng-model="rule.field">
<md-option ng-value="key" ng-repeat="(key, value) in fieldLabels">{{ value }}</md-option>
<md-option ng-value="key" ng-repeat="(key, value) in filterEditor.fieldLabels">{{ value }}</md-option>
</md-select>
</md-input-container>
@@ -62,7 +62,7 @@
<md-input-container flex="25" ng-show="rule.field == 'size'">
<md-select ng-model="rule.operator">
<md-option ng-value="key" ng-repeat="(key, value) in numberOperatorLabels">
<md-option ng-value="key" ng-repeat="(key, value) in filterEditor.numberOperatorLabels">
{{ value }}
</md-option>
</md-select>
@@ -70,18 +70,18 @@
<md-input-container flex="25" ng-show="rule.field != 'size'">
<md-select ng-model="rule.operator">
<md-option ng-value="key" ng-repeat="(key, value) in textOperatorLabels">
<md-option ng-value="key" ng-repeat="(key, value) in filterEditor.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 class="md-flex" md-no-float="md-no-float">
<input type="text" label:placeholder="Value" ng-model="rule.value"/>
</md-input-container>
<md-button class="sg-icon-button" type="button"
ng-click="removeMailFilterRule($index)">
ng-click="filterEditor.removeMailFilterRule($index)">
<md-icon>remove_circle</md-icon>
</md-button>
@@ -91,7 +91,7 @@
<div layout="row" layout-align="end center">
<md-button class="sg-icon-button" type="button"
ng-click="addMailFilterRule($event)">
ng-click="filterEditor.addMailFilterRule($event)">
<md-icon>add_circle</md-icon>
</md-button>
</div>
@@ -104,10 +104,10 @@
<md-list>
<md-list-item layout="row" layout-align="space-between center"
ng-repeat="action in filter.actions">
ng-repeat="action in filterEditor.filter.actions">
<md-input-container>
<md-select ng-model="action.method">
<md-option ng-value="key" ng-repeat="(key, value) in methodLabels">{{ value }}</md-option>
<md-option ng-value="key" ng-repeat="(key, value) in filterEditor.methodLabels">{{ value }}</md-option>
</md-select>
</md-input-container>
@@ -130,8 +130,10 @@
<!-- FILE INTO -->
<md-input-container ng-show="action.method == 'fileinto'" >
<md-select ng-model="action.argument">
<md-option ng-value="item.path" ng-repeat="item in mailboxes">
{{ item.name }}
<md-option ng-value="item.path" ng-repeat="item in filterEditor.mailboxes">
<div ng-class="'sg-child-level-' + item.level">
{{ item.name }}
</div>
</md-option>
</md-select>
</md-input-container>
@@ -153,7 +155,7 @@
<!-- nada -->
<md-button class="sg-icon-button" type="button"
ng-click="removeMailFilterAction($index)">
ng-click="filterEditor.removeMailFilterAction($index)">
<md-icon>remove_circle</md-icon>
</md-button>
@@ -162,15 +164,15 @@
<div layout="row" layout-align="end center">
<md-button class="sg-icon-button" type="button"
ng-click="addMailFilterAction($event)">
ng-click="filterEditor.addMailFilterAction($event)">
<md-icon>add_circle</md-icon>
</md-button>
</div>
</div>
</md-dialog-content>
<div class="md-actions">
<md-button type="button" ng-click="save()"><var:string label:value="Save"/></md-button>
</div>
<md-dialog-actions>
<md-button type="submit"><var:string label:value="Save"/></md-button>
</md-dialog-actions>
</form>
</md-dialog>
</container>
+30 -17
View File
@@ -24,29 +24,33 @@
<script type="text/ng-template" id="preferences.html">
<md-sidenav id="left-sidenav" class="md-sidenav-left md-whiteframe-z1" md-component-id="left" md-is-locked-open="$mdMedia('gt-md')" layout="column">
<var:component className="UIxSidenavToolbarTemplate" />
<md-content md-scroll-y="md-scroll-y" class="md-flex">
<md-content md-scroll-y="md-scroll-y" class="md-flex md-hue-2">
<md-list>
<md-list-item ng-click="app.go('general')"
ui-sref="preferences.general"
ui-sref-active="sg-active">
ui-sref-active="md-default-theme md-background md-bg md-hue-1">
<md-icon>settings</md-icon>
<p class="sg-item-name"><var:string label:value="General"/></p>
</md-list-item>
<var:if condition="userHasCalendarAccess">
<md-list-item ng-click="app.go('calendars')"
ui-sref="preferences.calendars"
ui-sref-active="sg-active">
ui-sref-active="md-default-theme md-background md-bg md-hue-1">
<md-icon>event</md-icon>
<p class="sg-item-name"><var:string label:value="Calendar"/></p>
</md-list-item>
</var:if>
<md-list-item ng-click="app.go('addressbooks')"
ui-sref="preferences.addressbooks"
ui-sref-active="sg-active">
ui-sref-active="md-default-theme md-background md-bg md-hue-1">
<md-icon>contacts</md-icon>
<p class="sg-item-name"><var:string label:value="Contacts"/></p>
</md-list-item>
<var:if condition="userHasMailAccess">
<md-list-item ng-click="app.go('mailer')"
ui-sref="preferences.mailer"
ui-sref-active="sg-active">
ui-sref-active="md-default-theme md-background md-bg md-hue-1">
<md-icon>email</md-icon>
<p class="sg-item-name"><var:string label:value="Mail"/></p>
</md-list-item>
</var:if>
@@ -58,7 +62,7 @@
<!-- TOP RIGHT TOOLBAR -->
<md-toolbar layout="row" layout-align="space-between start" class="md-tall">
<div class="md-toolbar-tools md-toolbar-tools-top sg-padded" layout="row" layout-align="space-between start">
<div class="md-toolbar-tools md-toolbar-tools-top" layout="row" layout-align="space-between start">
<var:component className="UIxTopnavToolbarTemplate" />
</div>
<md-button type="button" class="md-fab md-fab-bottom-right md-fab-overlap-bottom"
@@ -96,7 +100,8 @@
<div flex="50">
<md-input-container>
<label><var:string label:value="Language"/></label>
<md-select ng-model="app.preferences.defaults.SOGoLanguage">
<md-select ng-model="app.preferences.defaults.SOGoLanguage"
ng-change="app.onLanguageChange()">
<var:foreach list="languages" item="item">
<md-option var:value="item">
<var:string value="languageText"/>
@@ -180,6 +185,17 @@
</var:foreach>
</md-select>
</md-input-container>
<md-input-container>
<label><var:string label:value="Alternate Avatar"/></label>
<md-select ng-model="app.preferences.defaults.SOGoAlternateAvatar">
<var:foreach list="alternateAvatar" item="item">
<md-option var:value="item">
<var:string value="itemAlternateAvatarText"/>
</md-option>
</var:foreach>
</md-select>
</md-input-container>
</div>
</md-content>
</md-tab>
@@ -345,11 +361,10 @@
ng-repeat="item in
app.preferences.defaults.SOGoCalendarCategories
track by $index">
<i class="md-avatar" ng-style="{'background-color': app.preferences.defaults.SOGoCalendarCategoriesColors[item]}">
<sg-color-picker sg-on-select="app.preferences.defaults.SOGoCalendarCategoriesColors[item] = color"><!-- color picker--></sg-color-picker>
</i>
<sg-color-picker ng-model="app.preferences.defaults.SOGoCalendarCategoriesColors[item]"><!-- color picker--></sg-color-picker>
<md-input-container>
<input type="text" label:aria-label="Calendar Category" ng-model="app.preferences.defaults.SOGoCalendarCategories[$index]"/>
<input type="text" label:aria-label="Calendar Category"
ng-model="app.preferences.defaults.SOGoCalendarCategories[$index]"/>
</md-input-container>
<md-button class="sg-icon-button" type="button"
layout="row" layout-align="end center"
@@ -600,7 +615,7 @@
<input type="text" ng-model="app.preferences.defaults.SOGoSieveFilters[$index].name"/>
</md-input-container>
<md-button class="sg-icon-button" type="button"
ng-click="app.editMailFilter($index)"
ng-click="app.editMailFilter($event, $index)"
layout="row" layout-align="end center"
label:aria-label="Edit Filter">
<md-icon>edit</md-icon>
@@ -637,9 +652,7 @@
<md-list-item flex="50"
ng-repeat="(key, value) in
app.preferences.defaults.SOGoMailLabelsColors">
<i class="md-avatar" ng-style="{'background-color': value[1]}">
<sg-color-picker sg-on-select="value[1] = color"><!-- color picker--></sg-color-picker>
</i>
<sg-color-picker ng-model="value[1]"><!-- color picker--></sg-color-picker>
<md-input-container>
<input type="text"
label:aria-label="Label"
@@ -668,7 +681,7 @@
<!-- MAIL > ACCOUNTS -->
<md-tab id="mailAccountsTab"
aria-controls="mailAccountsTab-content"
label:label="Accounts">
label:label="IMAP Accounts">
<md-list class="sg-padded">
<md-list-item ng-repeat="item in
@@ -765,7 +778,7 @@
<var:string label:value="Do not send responses to mailing lists" />
</md-checkbox>
<div layout="row" layout-align="end center">
<div layout="row" layout-align="start center">
<md-checkbox
ng-model="app.preferences.defaults.Vacation.endDateEnabled"
ng-true-value="1"
@@ -4,9 +4,9 @@
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" flex-md="80" flex-sm="100">
<form name="eventForm" ng-submit="editor.save(eventForm)">
<md-toolbar class="sg-padded" ng-class="editor.component.getClassName('bg')">
<md-toolbar ng-class="editor.component.getClassName('bg')">
<div class="md-toolbar-tools">
<!-- summary -->
<md-icon ng-if="editor.component.classification == 'confidential'">visibility_off</md-icon>
@@ -23,191 +23,212 @@
</md-button>
</div>
</md-toolbar>
<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
md-selected-item="editor.categories.selected"
md-search-text="editor.categories.searchText"
md-items="category in editor.component.constructor.filterCategories(editor.categories.searchText)"
label:placeholder="Add a category">
<span md-highlight-text="editor.categories.searchText">{{category}}</span>
</md-autocomplete>
</md-chips>
<!-- classification -->
<md-radio-group layout="row" layout-align="space-around center"
ng-model="editor.component.classification">
<md-radio-button value="public">
<var:string label:value="label_Public"/>
</md-radio-button>
<md-radio-button value="confidential">
<var:string label:value="label_Confidential"/>
</md-radio-button>
<md-radio-button value="private">
<var:string label:value="label_Private"/>
</md-radio-button>
</md-radio-group>
<!-- priority -->
<div class="pseudo-input-container">
<label class="pseudo-input-label"><var:string label:value="Priority"/></label>
<md-slider class="md-flex"
md-discrete="true"
ng-model="editor.component.priority"
step="1"
min="0"
max="9"
label:aria-label="Priority"><!-- slider --></md-slider>
</div>
<!-- is all day -->
<md-checkbox
ng-model="editor.component.isAllDay"
ng-true-value="1"
ng-false-value="0"
label:aria-label="All day Event">
<var:string label:value="All day Event"/>
</md-checkbox>
<!-- is transparent -->
<md-checkbox
ng-model="editor.component.isTransparent"
ng-true-value="1"
ng-false-value="0"
label:aria-label="Show Time as Free">
<var:string label:value="Show Time as Free"/>
</md-checkbox>
<!-- send appointment notifications -->
<md-checkbox
ng-model="editor.component.sendAppointmentNotifications"
ng-true-value="1"
ng-false-value="0"
label:aria-label="Send Appointment Notifications">
<var:string label:value="Send Appointment Notifications"/>
</md-checkbox>
<!-- start + end -->
<div layout="row">
<md-dialog-content class="md-dialog-content">
<!-- location -->
<md-input-container>
<label><var:string label:value="From"/></label>
<input type="text" ng-model="editor.component.startDate" required="required"/>
<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="To"/></label>
<input type="text" ng-model="editor.component.endDate" required="required"/>
<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>
</div>
<!-- attach urls -->
<div class="attr" ng-repeat="attach in editor.component.attachUrls">
<div layout="row" layout-align="center end">
<md-input-container>
<label>
<var:string label:value="URL"/>
</label>
<input type="text" ng-model="attach.value"
sg-focus-on="attachUrl_{{$index}}"/>
</md-input-container>
<md-button class="sg-icon-button" type="button" ng-click="editor.component.deleteAttachUrl($index)">
<md-icon>remove_circle</md-icon>
<!-- categories -->
<md-chips ng-model="editor.component.categories">
<md-autocomplete
md-selected-item="editor.categories.selected"
md-search-text="editor.categories.searchText"
md-items="category in editor.component.constructor.filterCategories(editor.categories.searchText)"
md-min-length="0"
label:placeholder="Add a category">
<span md-highlight-text="editor.categories.searchText">{{category}}</span>
</md-autocomplete>
</md-chips>
<!-- classification -->
<md-radio-group layout="row" layout-align="space-around center"
ng-model="editor.component.classification">
<md-radio-button value="public">
<var:string label:value="label_Public"/>
</md-radio-button>
<md-radio-button value="confidential">
<var:string label:value="label_Confidential"/>
</md-radio-button>
<md-radio-button value="private">
<var:string label:value="label_Private"/>
</md-radio-button>
</md-radio-group>
<!-- priority -->
<div class="pseudo-input-container">
<label class="pseudo-input-label"><var:string label:value="Priority"/></label>
<md-slider class="md-flex"
md-discrete="true"
ng-model="editor.component.priority"
step="1"
min="0"
max="9"
label:aria-label="Priority"><!-- slider --></md-slider>
</div>
<!-- is all day -->
<md-checkbox
ng-model="editor.component.isAllDay"
ng-true-value="1"
ng-false-value="0"
label:aria-label="All day Event">
<var:string label:value="All day Event"/>
</md-checkbox>
<!-- is transparent -->
<md-checkbox
ng-model="editor.component.isTransparent"
ng-true-value="1"
ng-false-value="0"
label:aria-label="Show Time as Free">
<var:string label:value="Show Time as Free"/>
</md-checkbox>
<!-- send appointment notifications -->
<md-checkbox
ng-model="editor.component.sendAppointmentNotifications"
ng-true-value="1"
ng-false-value="0"
label:aria-label="Send Appointment Notifications">
<var:string label:value="Send Appointment Notifications"/>
</md-checkbox>
<!-- start + end -->
<div layout="row">
<div flex="50">
<div class="pseudo-input-container">
<label class="pseudo-input-label"><var:string label:value="From"/></label>
</div>
<div layout="row" layout-align="start center" layout-wrap="layout-wrap">
<md-datepicker ng-model="editor.component.start"
ng-change="editor.updateStartTime()"
label:md-placeholder="From"><!-- date picker --></md-datepicker>
<sg-timepicker ng-model="editor.component.start"
ng-change="editor.adjustStartTime()"
ng-hide="editor.component.isAllDay"><!-- time picker --></sg-timepicker>
</div>
</div>
<div flex="50">
<div class="pseudo-input-container">
<label class="pseudo-input-label"><var:string label:value="To"/></label>
</div>
<div layout="row" layout-align="start center" layout-wrap="layout-wrap">
<md-datepicker ng-model="editor.component.end"
ng-change="editor.updateEndTime()"
label:md-placeholder="To"><!-- date picker --></md-datepicker>
<sg-timepicker ng-model="editor.component.end"
ng-change="editor.adjustEndTime()"
ng-hide="editor.component.isAllDay"><!-- time picker --></sg-timepicker>
</div>
</div>
</div>
<!-- attach urls -->
<div class="attr" ng-repeat="attach in editor.component.attachUrls">
<div layout="row" layout-align="center end">
<md-input-container>
<label>
<var:string label:value="URL"/>
</label>
<input type="text" ng-model="attach.value"
sg-focus-on="attachUrl_{{$index}}"/>
</md-input-container>
<md-button class="sg-icon-button" type="button" ng-click="editor.component.deleteAttachUrl($index)">
<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.addAttachUrl($event)">
<md-icon>add_circle</md-icon>
</md-button>
<label class="button-label">
<var:string label:value="Attach"/>
</label>
</div>
<!-- comment -->
<md-input-container>
<label><var:string label:value="Description"/></label>
<textarea ng-model="editor.component.comment"><!-- comment --></textarea>
</md-input-container>
<!-- repeat -->
<div layout="row" layout-align="start end">
<div class="md-flex">
<md-input-container>
<label><var:string label:value="Repeat"/></label>
<md-select ng-model="editor.component.repeat.frequency" ng-disabled="editor.component.occurrenceId">
<var:foreach list="repeatList" item="item">
<md-option var:value="item"><var:string var:value="itemRepeatText"/></md-option>
</var:foreach>
</md-select>
</md-input-container>
</div>
<md-button type="button" class="sg-icon-button"
label:aria-label="repeat_CUSTOM"
ng-disabled="editor.component.occurrenceId"
ng-show="editor.component.repeat.frequency != 'never'"
ng-click="editor.toggleRecurrenceEditor()">
<md-icon ng-class="{'md-rotate-45': editor.showRecurrenceEditor}">add</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.addAttachUrl($event)">
<md-icon>add_circle</md-icon>
</md-button>
<label class="button-label">
<var:string label:value="Attach"/>
</label>
</div>
<!-- comment -->
<md-input-container>
<label><var:string label:value="Description"/></label>
<textarea ng-model="editor.component.comment"><!-- comment --></textarea>
</md-input-container>
<!-- repeat -->
<div layout="row" layout-align="start end">
<div class="md-flex">
<md-input-container>
<label><var:string label:value="Repeat"/></label>
<md-select ng-model="editor.component.repeat.frequency" ng-disabled="editor.component.occurrenceId">
<var:foreach list="repeatList" item="item">
<md-option var:value="item"><var:string var:value="itemRepeatText"/></md-option>
</var:foreach>
</md-select>
<div ng-show="editor.showRecurrenceEditor" class="sg-subcontent">
<var:component className="UIxRecurrenceEditor" />
</div>
<!-- end repeat -->
<div layout="row" layout-align="start end">
<div ng-show="editor.component.repeat.frequency != 'never'">
<md-input-container>
<label><var:string label:value="End Repeat"/></label>
<md-select ng-model="editor.component.repeat.end"
ng-disabled="editor.component.occurrenceId">
<md-option value="never"><var:string label:value="Never"/></md-option>
<md-option value="count"><var:string label:value="After"/></md-option>
<md-option value="until"><var:string label:value="On Date"/></md-option>
</md-select>
</md-input-container>
</div>
<div layout="row" layout-align="start center" ng-show="editor.component.repeat.end == 'count'">
<md-input-container class="md-input-number">
<input type="number" label:aria-label="times" ng-model="editor.component.repeat.count"/>
</md-input-container>
<var:string label:value="times"/>
</div>
<md-input-container ng-show="editor.component.repeat.end == 'until'">
<input type="date" label:aria-label="Repeat until" ng-model="editor.component.repeat.until"/>
</md-input-container>
</div>
<md-button type="button" class="sg-icon-button"
label:aria-label="repeat_CUSTOM"
ng-show="editor.component.repeat.frequency != 'never'"
ng-click="editor.toggleRecurrenceEditor()">
<md-icon ng-class="{'md-rotate-45': editor.showRecurrenceEditor}">add</md-icon>
</md-button>
</div>
<div ng-show="editor.showRecurrenceEditor" class="sg-subcontent">
<var:component className="UIxRecurrenceEditor" />
</div>
<!-- end repeat -->
<div layout="row" layout-align="start end">
<div ng-show="editor.component.repeat.frequency != 'never'">
<md-input-container>
<label><var:string label:value="End Repeat"/></label>
<md-select ng-model="editor.component.repeat.end">
<md-option value="never"><var:string label:value="Never"/></md-option>
<md-option value="count"><var:string label:value="After"/></md-option>
<md-option value="until"><var:string label:value="On Date"/></md-option>
</md-select>
</md-input-container>
<!-- attendees -->
<div layout="row" layout-align="start start">
<md-autocomplete class="md-flex"
label:md-floating-label="Invite Attendees"
md-selected-item="attendeeToAdd"
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-min-length="3"
md-delay="300"
md-no-cache="true"
sg-enter="editor.addAttendee(editor.searchText)">
<md-item-template>
<div class="md-contact-suggestion">
<span class="md-contact-name"
md-highlight-text="editor.searchText"
md-highlight-flags="^i">{{card.$$fullname}}</span>
<span class="md-contact-email"
md-highlight-text="editor.searchText"
md-highlight-flags="^i">{{card.$$email}}</span>
</div>
</md-item-template>
</md-autocomplete>
<md-button type="button" class="sg-icon-button"
label:aria-label="repeat_CUSTOM"
ng-click="editor.toggleAttendeesEditor()">
<md-icon ng-class="{'md-rotate-180': editor.showAttendeesEditor}">expand_more</md-icon>
</md-button>
</div>
<div layout="row" layout-align="start center" ng-show="editor.component.repeat.end == 'count'">
<md-input-container class="md-input-number">
<input type="number" label:aria-label="times" ng-model="editor.component.repeat.count"/>
</md-input-container>
<var:string label:value="times"/>
</div>
<md-input-container ng-show="editor.component.repeat.end == 'until'">
<input type="date" label:aria-label="Repeat until" ng-model="editor.component.repeat.until"/>
</md-input-container>
</div>
<!-- attendees -->
<div layout="row" layout-align="start start">
<md-autocomplete class="md-flex"
label:md-floating-label="Invite Attendees"
md-selected-item="attendeeToAdd"
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-min-length="3"
md-delay="300"
md-no-cache="true"
sg-enter="editor.addAttendee(editor.searchText)">
<md-item-template>
<div class="md-contact-suggestion" layout="row" layout-align="space-between center">
<span class="md-contact-name"
md-highlight-text="editor.searchText"
md-highlight-flags="^i">{{card.$$fullname}}</span>
<span class="md-contact-email"
md-highlight-text="editor.searchText"
md-highlight-flags="^i">{{card.$$email}}</span>
</div>
</md-item-template>
</md-autocomplete>
<md-button type="button" class="sg-icon-button"
label:aria-label="repeat_CUSTOM"
ng-click="editor.toggleAttendeesEditor()">
<md-icon ng-class="{'md-rotate-180': editor.showAttendeesEditor}">expand_more</md-icon>
</md-button>
</div>
<!-- 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"
@@ -215,37 +236,42 @@
ng-hide="editor.showAttendeesEditor"
readonly="true">
<md-chip-template>
<div class="md-contact-avatar"><img src="#" ng-src="{{$chip.image}}" alt="{{$chip.name}}"/></div>
<div class="md-contact-name">{{$chip.name}}</div>
<div class="md-contact-avatar">
<sg-avatar-image sg-email="$chip.email" size="32"><!-- avatar --></sg-avatar-image>
</div>
<div class="md-contact-name">{{$chip.name || $chip.email}}</div>
<md-icon ng-class="'icon-' + $chip.status"><!-- partstat --></md-icon>
<md-icon class="sg-chip-remove"
label:aria-label="Delete"
ng-click="editor.component.deleteAttendee($chip)">close</md-icon>
</md-chip-template>
</md-chips>
<div ng-show="editor.showAttendeesEditor" class="sg-subcontent attendees">
<var:component className="UIxAttendeesEditor" />
</div>
<!-- reminder -->
<md-checkbox ng-model="editor.component.$hasAlarm"
label:aria-label="Reminder">
<var:string label:value="Reminder"/>
</md-checkbox>
<div class="sg-subcontent"
ng-show="editor.component.$hasAlarm">
<var:component className="UIxReminderEditor" />
</div>
</md-dialog-content>
<div ng-show="editor.showAttendeesEditor" class="attendees">
<var:component className="UIxAttendeesEditor" />
</div>
<!-- reminder -->
<md-checkbox ng-model="editor.component.$hasAlarm"
label:aria-label="Reminder">
<var:string label:value="Reminder"/>
</md-checkbox>
<div class="sg-subcontent"
ng-show="editor.component.$hasAlarm">
<var:component className="UIxReminderEditor" />
</div>
</md-dialog-content>
<!-- cancel/reset/save -->
<div class="md-actions">
<md-dialog-actions>
<md-button type="button" ng-click="editor.cancel()">
<var:string label:value="Cancel"/>
</md-button>
<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"
<md-button class="md-primary" type="submit"
ng-disabled="editor.eventForm.$invalid">
<var:string label:value="Save"/>
</md-button>
</div>
</form>
</md-dialog>
</md-dialog-actions>
</form>
</md-dialog>
</container>
@@ -4,25 +4,38 @@
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')">
<div class="md-toolbar-tools">
<md-icon class="material-icons sg-icon-toolbar-bg">event</md-icon>
<div class="sg-md-title 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>
<!-- summary -->
{{::editor.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 aria-label="Close dialog">close</md-icon>
</md-button>
<md-dialog flex="40" flex-md="80" flex-sm="100">
<md-toolbar ng-class="editor.component.getClassName('bg')">
<div class="md-toolbar-tools">
<md-icon class="material-icons sg-icon-toolbar-bg">event</md-icon>
<div class="sg-md-title 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>
<!-- summary -->
{{::editor.component.summary}}
<!-- priority -->
<md-icon ng-repeat="i in ::editor.component.priority | range">star</md-icon>
</div>
</md-toolbar>
<md-dialog-content>
<md-menu>
<md-button label:aria-label="More options" class="sg-icon-button" ng-click="$mdOpenMenu($event)">
<md-icon>more_vert</md-icon>
</md-button>
<md-menu-content>
<md-menu-item>
<md-button label:aria-label="View Raw Source"
ng-click="editor.viewRawSource($event)">
<var:string label:value="View Raw Source"/>
</md-button>
</md-menu-item>
</md-menu-content>
</md-menu>
<md-button class="md-icon-button" ng-click="editor.close()">
<md-icon label:aria-label="Close">close</md-icon>
</md-button>
</div>
</md-toolbar>
<md-dialog-content>
<md-list>
<!-- categories -->
<md-list-item ng-show="editor.component.categories.length > 0">
@@ -45,17 +58,15 @@
<!-- start/end dates -->
<md-list-item ng-class="{ 'md-2-line': editor.component.isAllDay, 'md-3-line': !editor.component.isAllDay }">
<md-icon>access_time</md-icon>
<div layout="row" class="md-flex">
<div class="md-list-item-text" ng-show="editor.component.startDate">
<p><var:string label:value="Start"/></p>
<h3>{{::editor.component.localizedStartDate}}</h3>
<h3 ng-hide="editor.component.isAllDay">{{::editor.component.localizedStartTime}}</h3>
</div>
<div class="md-list-item-text" ng-show="editor.component.endDate">
<p><var:string label:value="End"/></p>
<h3>{{::editor.component.localizedEndDate}}</h3>
<h3 ng-hide="editor.component.isAllDay">{{::editor.component.localizedEndTime}}</h3>
</div>
<div class="md-list-item-text" ng-show="editor.component.startDate">
<p><var:string label:value="Start"/></p>
<h3>{{::editor.component.localizedStartDate}}</h3>
<h3 ng-hide="editor.component.isAllDay">{{::editor.component.localizedStartTime}}</h3>
</div>
<div class="md-list-item-text" ng-show="editor.component.endDate">
<p><var:string label:value="End"/></p>
<h3>{{::editor.component.localizedEndDate}}</h3>
<h3 ng-hide="editor.component.isAllDay">{{::editor.component.localizedEndTime}}</h3>
</div>
</md-list-item>
<!-- is transparent -->
@@ -81,14 +92,14 @@
<!-- repeat -->
<md-list-item ng-show="editor.component.$isRecurrent">
<md-icon>repeat</md-icon>
<p><!-- editor.component.repeat.toString() --></p>
<p>{{editor.component.repeatDescription()}}</p>
</md-list-item>
<!-- reminder -->
<md-list-item ng-show="editor.component.$hasAlarm" ng-hide="editor.component.userHasRSVP">
<md-list-item ng-hide="!editor.component.$hasAlarm || editor.component.userHasRSVP">
<md-icon>alarm_on</md-icon>
<p><!-- editor.component.alarm.toString() --></p>
<p>{{editor.component.alarmDescription()}}</p>
</md-list-item>
<md-list-item class="md-2-line" ng-show="editor.component.organizer">
<md-list-item layout-align="start start" ng-show="editor.component.organizer">
<md-icon>people</md-icon>
<div layout="column" layout-fill="layout-fill">
<!-- organizer -->
@@ -98,7 +109,9 @@
ng-model="::editor.organizer"
readonly="true">
<md-chip-template>
<div class="md-contact-avatar"><img src="#" ng-src="{{$chip.$image}}" alt="{{$chip.name}}"/></div>
<div class="md-contact-avatar">
<sg-avatar-image sg-email="$chip.email" size="32"><!-- avatar --></sg-avatar-image>
</div>
<div class="md-contact-name">{{$chip.name}}</div>
</md-chip-template>
</md-chips>
@@ -112,7 +125,9 @@
ng-model="::editor.component.attendees"
readonly="true">
<md-chip-template>
<div class="md-contact-avatar"><img src="#" ng-src="{{$chip.image}}" alt="{{$chip.name}}"/></div>
<div class="md-contact-avatar">
<sg-avatar-image sg-email="$chip.email" size="32"><!-- avatar --></sg-avatar-image>
</div>
<div class="md-contact-name">{{$chip.name}}</div>
<md-icon ng-class="'icon-' + $chip.status"><!-- partstat --></md-icon>
</md-chip-template>
@@ -123,7 +138,7 @@
</md-list>
<!-- invitation -->
<md-list ng-show="editor.component.userHasRSVP">
<md-divider><!-- dividerd --></md-divider>
<md-divider><!-- divider --></md-divider>
<md-subheader class="md-no-sticky sg-padded--top"><var:string label:value="You are invited to participate"/></md-subheader>
<!-- participation status -->
<md-list-item>
@@ -170,32 +185,96 @@
<span ng-show="editor.component.$hasAlarm"><var:component className="UIxReminderEditor" /></span>
</div>
</md-dialog-content>
<!-- actions -->
<div class="md-actions" ng-show="editor.component.isEditable()">
<!-- editable but not recurrent -->
<md-dialog-actions ng-show="editor.component.isEditable()">
<md-button class="md-warn"
label:aria-label="Delete Event"
ng-click="editor.deleteAllOccurrences()">
<var:string label:value="Delete"/>
</md-button>
<div class="md-flex"><!-- spacer --></div>
<md-button type="button" ng-click="editor.edit()">
<var:string label:value="Edit"/>
</md-button>
</div>
<div class="md-actions" ng-show="editor.component.isEditableOccurrence()">
</md-dialog-actions>
<!-- editable and recurrent -->
<md-dialog-actions ng-show="editor.component.isEditableOccurrence()">
<md-menu>
<md-button class="md-warn"
label:aria-label="Delete Event"
ng-click="$mdOpenMenu()"
md-menu-origin="md-menu-origin">
<var:string label:value="Delete"/> <md-icon>arrow_drop_down</md-icon>
</md-button>
<md-menu-content>
<md-menu-item>
<md-button class="md-warn"
ng-click="editor.deleteOccurrence()">
<var:string label:value="Delete This Occurrence"/>
</md-button>
</md-menu-item>
<md-menu-item>
<md-button class="md-warn"
ng-click="editor.deleteAllOccurrences()">
<var:string label:value="Delete All Occurrences"/>
</md-button>
</md-menu-item>
</md-menu-content>
</md-menu>
<div class="md-flex"><!-- spacer --></div>
<md-button type="button" ng-click="editor.editAllOccurrences()">
<var:string label:value="Edit All Occurrences"/>
</md-button>
<md-button type="button" ng-click="editor.edit()">
<var:string label:value="Edit This Occurrence"/>
</md-button>
</div>
<div class="md-actions" ng-show="editor.component.isInvitation()">
</md-dialog-actions>
<!-- invitation but not recurrent -->
<md-dialog-actions ng-show="editor.component.isInvitation()">
<md-button class="md-warn"
label:aria-label="Delete Event"
ng-click="editor.deleteAllOccurrences()">
<var:string label:value="Delete"/>
</md-button>
<div class="md-flex"><!-- spacer --></div>
<md-button type="button" ng-click="editor.reply()">
<var:string label:value="Update"/>
</md-button>
</div>
<div class="md-actions" ng-show="editor.component.isInvitationOccurrence()">
</md-dialog-actions>
<!-- invitation and recurrent -->
<md-dialog-actions ng-show="editor.component.isInvitationOccurrence()">
<md-menu>
<md-button class="md-warn"
label:aria-label="Delete Event"
ng-click="$mdOpenMenu()"
md-menu-origin="md-menu-origin">
<var:string label:value="Delete"/>
</md-button>
<md-menu-content>
<md-menu-item>
<md-button class="md-warn"
ng-click="editor.deleteOccurrence()">
<var:string label:value="Delete This Occurrence"/>
</md-button>
</md-menu-item>
<md-menu-item>
<md-button class="md-warn"
ng-click="editor.deleteAllOccurrences()">
<var:string label:value="Delete All Occurrences"/>
</md-button>
</md-menu-item>
</md-menu-content>
</md-menu>
<div class="md-flex"><!-- spacer --></div>
<md-button type="button" ng-click="editor.replyAllOccurrences()">
<var:string label:value="Update All Occurrences"/>
</md-button>
<md-button type="button" ng-click="editor.reply()">
<var:string label:value="Update This Occurrence"/>
</md-button>
</div>
</md-dialog-actions>
</md-dialog>
</container>
@@ -14,15 +14,21 @@
<!-- attendees -->
<md-list>
<md-list-item>
<div><!-- empty --></div>
<div class="md-tile-left"><!-- empty --></div>
</md-list-item>
<md-list-item ng-repeat="currentAttendee in editor.component.attendees track by currentAttendee.email">
<sg-avatar-image sg-email="currentAttendee.email"
size="32"><!-- avatar --></sg-avatar-image>
<sg-avatar-image class="md-avatar"
sg-email="currentAttendee.email"
size="40"><!-- avatar --></sg-avatar-image>
<div class="sg-tile-content">
<div class="sg-md-subhead-multi">{{currentAttendee.name}}</div>
<div class="sg-md-body-multi">{{currentAttendee.email}}</div>
<div class="sg-md-subhead"><div>{{currentAttendee.name}}</div></div>
<div class="sg-md-body"><div>{{currentAttendee.email}}</div></div>
</div>
<md-button class="md-icon-button"
label:aria-label="Delete"
ng-click="editor.component.deleteAttendee(currentAttendee)">
<md-icon>close</md-icon>
</md-button>
</md-list-item>
</md-list>
<!-- freebusy -->
+104 -94
View File
@@ -1,115 +1,125 @@
<?xml version="1.0" standalone="yes"?>
<!DOCTYPE container>
<container
xmlns="http://www.w3.org/1999/xhtml"
xmlns:var="http://www.skyrix.com/od/binding"
xmlns:const="http://www.skyrix.com/od/constant"
xmlns:rsrc="OGo:url"
xmlns:label="OGo:label">
<div var:class="daysViewClasses">
xmlns="http://www.w3.org/1999/xhtml"
xmlns:var="http://www.skyrix.com/od/binding"
xmlns:const="http://www.skyrix.com/od/constant"
xmlns:rsrc="OGo:url"
xmlns:label="OGo:label">
<md-toolbar class="daysView md-hue-1" var:sg-view="currentView">
<!-- MultiColumnView -->
<!-- Display the name of the calendar -->
<var:if condition="isMultiColumnView">
<div class="calendarLabels">
<var:foreach list="calendarsToDisplay" item="currentCalendar">
<div class="calendarsToDisplay" var:folder="currentCalendar.folder">
<var:string value="labelForCalendar"/>
</div>
</var:foreach>
</div>
<!-- Display today abreviation and date -->
<div class="days dayLabels">
<var:foreach list="daysToDisplay" item="currentTableDay">
<div var:class="dayClasses">
<var:string value="labelForDate"/><br/>
<span class="dayOfWeek"><var:string value="labelForDay"/></span>
</div>
</var:foreach>
</div>
<!-- All day cells -->
<div class="days">
<var:foreach list="calendarsToDisplay" item="currentCalendar">
<var:foreach list="daysToDisplay" item="currentTableDay">
<div var:class="dayClasses" var:day="currentTableDay.shortDateString" var:id="currentAllDayId" var:calendar="currentCalendar.folder" hour="allday"><!-- space --></div>
</var:foreach>
</var:foreach>
</div>
</var:if>
<!-- Display today abreviation and date -->
<div class="days dayLabels">
<var:foreach list="daysToDisplay" item="currentTableDay">
<div var:class="dayClasses">
<!-- Week view day header -->
<var:if condition="isWeekView">
<div class="sg-md-caption md-default-theme md-fg md-primary md-hue-1"><var:string value="labelForDay"/></div>
<var:if condition="currentTableDay.isToday">
<div class="sg-md-display-2 md-default-theme md-fg md-accent md-hue-2"><var:string value="currentTableDay.dayOfMonth"/></div>
</var:if>
<var:if condition="currentTableDay.isToday" const:negate="YES">
<div class="sg-md-display-2--thin md-default-theme md-fg md-hue-2"><var:string value="currentTableDay.dayOfMonth"/></div>
</var:if>
<div class="md-default-theme md-fg md-primary md-hue-2"><var:string value="labelForMonth"/></div>
</var:if>
<!-- DayView or WeekView -->
<var:if condition="isNotMultiColumnView">
<!-- Display today abreviation and date -->
<div class="days dayLabels">
<var:foreach list="daysToDisplay" item="currentTableDay">
<div var:class="dayClasses">
<var:string value="labelForDate"/><br/>
<span class="dayOfWeek"><var:string value="labelForDay"/></span>
</div>
</var:foreach>
</div>
<!-- All day cells -->
<div class="days">
<var:foreach list="daysToDisplay" item="currentTableDay">
<div var:class="dayClasses" var:day="currentTableDay.shortDateString" var:id="currentAllDayId" hour="allday"><!-- space --></div>
</var:foreach>
</div>
</var:if>
</div>
<!-- The hours cells -->
<div var:class="daysViewClasses">
<div class="hours">
<var:foreach list="hoursToDisplay" item="currentTableHour">
<div class="hour" var:id="currentHourId">
<var:string value="currentTableHour"/>
<!-- Day view header -->
<var:if condition="isWeekView" const:negate="YES">
<var:if condition="currentTableDay.isToday">
<div class="sg-md-display-4 md-default-theme md-fg md-accent md-hue-2"><var:string value="currentTableDay.dayOfMonth"/></div>
</var:if>
<var:if condition="currentTableDay.isToday" const:negate="YES">
<div class="sg-md-display-4 md-default-theme md-fg md-hue-2"><var:string value="currentTableDay.dayOfMonth"/></div>
</var:if>
<div class="md-default-theme md-fg md-primary md-hue-2"><var:string value="labelForMonth"/></div>
</var:if>
</div>
</var:foreach>
</div>
<div class="days">
<!-- MultiColumnView -->
<var:if condition="isMultiColumnView">
<var:foreach list="calendarsToDisplay" item="currentCalendar">
<var:if condition="isMultiColumnView">
<!-- Calendars names in multicolumn day view -->
<div class="days">
<div class="day multicolumnDay"
ng-repeat="view in calendar.views"
ng-class="view.calendar.getClassName('bdr')">
{{view.calendar.name}}
</div>
</div>
</var:if>
<!-- All day cells -->
<div class="allDaysView md-default-theme md-background md-bg">
<div class="days" sg-calendar-scroll-view="multiday-allday">
<var:foreach list="daysToDisplay" item="currentTableDay">
<sg-calendar-day var:class="dayClasses"
var:day="currentTableDay.shortDateString"
var:id="currentAllDayId"
hour="allday"
var:sg-day-number="currentDayNumber"
var:sg-day="currentTableDay.shortDateString"
var:sg-day-string="currentTableDay.iso8601DateString"
ng-repeat="view in calendar.views">
<sg-calendar-day-table
sg-blocks="view.allDayBlocks"
sg-click="list.openEvent(event, component)"
var:sg-day="currentTableDay.shortDateString"><!-- blocks for current day --></sg-calendar-day-table>
<sg-calendar-day-block
sg-calendar-ghost="sg-calendar-ghost"
sg-block="list.component.$ghost"><!-- drag ghost --></sg-calendar-day-block>
</sg-calendar-day>
</var:foreach>
</div>
</div>
</md-toolbar>
<md-content class="md-flex" sg-calendar-scroll-view="multiday">
<div class="calendarView">
<!-- The hours -->
<div class="hours">
<var:foreach list="hoursToDisplay" item="currentTableHour">
<div class="hour" var:id="currentHourId">
<var:string value="currentTableHour"/>
</div>
</var:foreach>
</div>
<!-- The quarters grid -->
<div class="daysView">
<div class="days">
<var:foreach list="daysToDisplay" item="currentTableDay">
<div var:class="dayClasses" var:id="currentDayId" var:day-number="currentDayNumber" var:calendar="currentCalendar.folder" var:day="currentTableDay.shortDateString">
<sg-calendar-day var:class="dayClasses"
var:id="currentDayId"
var:sg-day-number="currentDayNumber"
var:sg-day="currentTableDay.shortDateString"
var:sg-day-string="currentTableDay.iso8601DateString"
ng-repeat="view in calendar.views">
<div class="hourCells">
<var:foreach list="hoursToDisplay" item="currentTableHour">
<div var:class="clickableHourCellClass" var:day="currentTableDay.shortDateString" var:hour="currentAppointmentHour">
<div var:class="clickableHourCellClass"
sg-draggable-calendar-block="sg-draggable-calendar-block"
var:sg-hour="currentAppointmentHour">
<span class="minutes15"><!-- space --></span>
<span class="minutes30"><!-- space --></span>
<span class="minutes45"><!-- space --></span>
</div>
</var:foreach>
<sg-calendar-day-table
sg-click="list.openEvent(event, component)"
sg-blocks="view.blocks"
var:sg-day-number="currentDayNumber"
var:sg-day="currentTableDay.shortDateString"><!-- blocks for current day --></sg-calendar-day-table>
<sg-calendar-day-block
sg-calendar-ghost="sg-calendar-ghost"
sg-block="list.component.$ghost"><!-- drag ghost --></sg-calendar-day-block>
</div>
<div class="events"><!-- space --></div>
</div>
</sg-calendar-day>
</var:foreach>
</var:foreach>
</var:if>
<var:if condition="isNotMultiColumnView">
<var:foreach list="daysToDisplay" item="currentTableDay">
<div var:class="dayClasses" var:id="currentDayId" var:day-number="currentDayNumber" var:day="currentTableDay.shortDateString">
<div class="hourCells">
<var:foreach list="hoursToDisplay" item="currentTableHour">
<div var:class="clickableHourCellClass" var:day="currentTableDay.shortDateString" var:hour="currentAppointmentHour">
<span class="minutes15"><!-- space --></span>
<span class="minutes30"><!-- space --></span>
<span class="minutes45"><!-- space --></span>
</div>
</var:foreach>
<sg-calendar-day-table
sg-blocks="calendar.blocks"
sg-click="list.openEvent(event, component)"
var:sg-day="currentTableDay.shortDateString" />
</div>
<div class="events"><!-- space --></div>
</div>
</var:foreach>
</var:if>
</div>
</div>
</div>
</div>
</md-content>
</container>
+45 -45
View File
@@ -1,47 +1,47 @@
<?xml version="1.0" standalone="yes"?>
<container
xmlns="http://www.w3.org/1999/xhtml"
xmlns:var="http://www.skyrix.com/od/binding"
xmlns:const="http://www.skyrix.com/od/constant"
xmlns:rsrc="OGo:url"
xmlns:label="OGo:label">
<!DOCTYPE container>
<container
xmlns="http://www.w3.org/1999/xhtml"
xmlns:var="http://www.skyrix.com/od/binding"
xmlns:const="http://www.skyrix.com/od/constant"
xmlns:rsrc="OGo:url"
xmlns:label="OGo:label">
<!-- <div class="menu" id="currentViewMenu">
<ul>
<li><var:string label:value="New Event..."/></li>
<li><var:string label:value="New Task..."/></li>
<li>!- separator -</li>
<li><var:string label:value="Previous Day"/></li>
<li><var:string label:value="Next Day"/></li>
<li>!- separator -</li>
<li><var:string label:value="Delete Event"/></li>
<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>
</container>
<md-toolbar hide-sm="hide-sm">
<div class="md-toolbar-tools">
<md-button class="md-icon-button"
label:aria-label="Previous Day"
var:date="prevDayQueryParameters.day"
ng-click="calendar.changeView($event)"><md-icon>chevron_left</md-icon></md-button>
<div><var:string value="currentDayName" /></div>
<md-button class="md-icon-button"
label:aria-label="Next Day"
var:date="nextDayQueryParameters.day"
ng-click="calendar.changeView($event)"><md-icon>chevron_right</md-icon></md-button>
<div class="md-flex"><!-- spacer --></div>
<md-button class="md-icon-button md-accent"
label:aria-label="Today"
ng-click="app.today()"><md-icon>today</md-icon></md-button>
<a class="md-icon-button md-button"
label:aria-label="Day"
ng-disabled="true"
href="#/calendar/day"><md-icon>view_day</md-icon></a>
<a class="md-icon-button md-button"
label:aria-label="Week"
href="#/calendar/week"><md-icon>view_week</md-icon></a>
<a class="md-icon-button md-button"
label:aria-label="Month"
href="#/calendar/month"><md-icon>view_module</md-icon></a>
<a class="md-icon-button md-button"
label:aria-label="Multicolumn Day View"
href="#/calendar/multicolumnday"><md-icon>view_array</md-icon></a>
</div>
</md-toolbar>
<var:component
className="UIxCalDayTable"
startDate="startDate"
const:CSSClass="dayOverview"
const:numberOfDays="1"
const:currentView="dayview"/>
</container>
+427 -324
View File
@@ -8,7 +8,7 @@
xmlns:label="OGo:label"
className="UIxPageFrame"
title="title"
const:jsFiles="Common.js, Preferences.services.js, Contacts.services.js, Mailer.services.js, Scheduler.js, Scheduler.services.js">
const:jsFiles="Common.js, Preferences.services.js, Contacts.services.js, Mailer.services.js, vendor/angular-file-upload.min.js, Scheduler.js, Scheduler.services.js">
<script type="text/javascript">
var firstDayOfWeek = <var:string value="firstDayOfWeek"/>;
var dayStartHour = <var:string value="dayStartHour"/>;
@@ -106,101 +106,101 @@
<p><span class="label"><var:string label:value="Created by" /></span> <span>!- space -</span></p>
<p class="description">!- space -</p>
</div>
</div>
<div id="uploadDialog" style="display: none" class="dialog left">
<div>
<h3><var:string label:value="Import Events"/></h3>
<p class="prompt"><var:string label:value="Select an iCalendar file (.ics)."/></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="calendarFile" class="textField" id="calendarFile" />
<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" style="display: none" class="dialog left">
<div>
<h3><var:string label:value="Import Events"/></h3>
<p><span id="uploadResultsContent">!- empty -</span>
<a href="#" class="button" const:id="uploadOK">
<span><var:string label:value="Done" /></span></a></p>
<hr/>
</div>
</div>
-->
-->
<main class="view layout-fill" ui-view="calendars" layout="row" ng-controller="navController"><!-- calendars list --></main>
<script type = "text/ng-template" id="UIxCalMainFrame">
<script type="text/ng-template" id="UIxCalMainView">
<!-- calendars colors -->
<div sg-folder-stylesheet="true"
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>
<sg-folder-stylesheet
ng-repeat="calendar in app.service.$findAll()"
ng-model="calendar"><!-- stylesheet --></sg-folder-stylesheet>
<!-- calendars colors -->
<sg-category-stylesheet
ng-repeat="category in app.categories"
ng-model="category"><!-- stylesheet --></sg-category-stylesheet>
<!-- Sidenav -->
<md-sidenav id="left-sidenav" class="md-sidenav-left md-whiteframe-z1" md-component-id="left" md-is-locked-open="isGtMedium" layout="column">
<md-sidenav class="md-sidenav-left md-whiteframe-z1" layout="column"
md-component-id="left" md-is-locked-open="isGtMedium"
ng-class="{ 'sg-closed': leftIsClose }">
<var:component className="UIxSidenavToolbarTemplate" />
<md-content md-scroll-y="md-scroll-y" class="md-flex">
<md-content md-scroll-y="md-scroll-y" class="md-flex md-hue-2">
<!-- User's calendars -->
<section>
<md-subheader class="sg-md-subheader">
<section class="sg-section-list">
<md-subheader class="md-hue-2">
<div layout="row" layout-align="space-between center">
<span><var:string label:value="Calendars"/></span>
<md-button class="sg-icon-button"
label:aria-label="New Calendar..."
ng-click="calendars.newCalendar()">
ng-click="app.newCalendar()">
<md-icon>add_circle_outline</md-icon>
</md-button>
</div>
</md-subheader>
<md-list>
<md-list-item ng-repeat="calendar in calendars.service.$calendars">
<md-list-item ng-repeat="calendar in app.service.$calendars"
ng-dblclick="app.editFolder(calendar)">
<md-checkbox ng-model="calendar.active"
ng-class="calendar.getClassName('checkbox')"
ng-true-value="1"
ng-false-value="0"
label:aria-label="Enable"><!-- enable --></md-checkbox>
<p class="sg-item-name">{{calendar.name}}</p>
<p class="sg-item-name" ng-show="app.editMode != calendar.id">
{{calendar.name}}
<span class="sg-counter-badge" ng-show="calendar.activeTasks">{{calendar.activeTasks}}</span>
</p>
<md-input-container class="md-flex"
ng-show="app.editMode == calendar.id">
<input class="sg-item-name" type="text"
label:aria-label="Name of the Calendar"
ng-model="calendar.name"
ng-blur="app.renameFolder(calendar)"
sg-focus-on="calendarName_{{calendar.id}}"
sg-enter="app.renameFolder(calendar)"
sg-escape="app.revertEditing(calendar)"/>
</md-input-container>
<md-menu class="md-secondary" label:aria-label="Options">
<md-icon label:aria-label="Options"
ng-click="$mdOpenMenu()"
md-menu-origin="md-menu-origin">more_vert</md-icon>
<md-button class="md-icon-button" label:aria-label="Options"
ng-click="$mdOpenMenu()"
md-menu-origin="md-menu-origin">
<md-icon>more_vert</md-icon>
</md-button>
<md-menu-content width="2">
<md-menu-item>
<md-button ng-click="calendars.confirmDelete(calendar)">
<md-button type="button" ng-click="app.editFolder(calendar)">
<var:string label:value="Rename"/>
</md-button>
</md-menu-item>
<md-menu-item ng-show="calendar.id != 'personal'">
<md-button ng-click="app.confirmDelete(calendar)">
<var:string label:value="Delete"/>
</md-button>
</md-menu-item>
<md-menu-item>
<md-button ng-click="calendars.exportCalendar()">
<md-button ng-click="app.importCalendar($event, calendar)">
<var:string label:value="Import"/>
</md-button>
</md-menu-item>
<md-menu-item>
<md-button ng-click="app.exportCalendar(calendar)">
<var:string label:value="Export"/>
</md-button>
</md-menu-item>
<md-menu-divider><!-- divider --></md-menu-divider>
<md-menu-item>
<md-button ng-click="calendars.showLinks(calendar)">
<md-button ng-click="app.showLinks(calendar)">
<var:string label:value="Links to this Calendar"/>
</md-button>
</md-menu-item>
<md-menu-item>
<md-button ng-click="calendars.share(calendar)">
<md-button ng-click="app.share(calendar)">
<var:string label:value="Sharing..."/>
</md-button>
</md-menu-item>
<md-menu-divider><!-- divider --></md-menu-divider>
<md-menu-item>
<md-button ng-click="calendars.showProperties(calendar)">
<md-button ng-click="app.showProperties(calendar)">
<var:string label:value="Properties"/>
</md-button>
</md-menu-item>
@@ -210,45 +210,66 @@
</md-list>
</section>
<!-- Subscriptions -->
<section>
<md-subheader class="sg-md-subheader">
<section class="sg-section-list">
<md-subheader class="md-hue-2">
<div layout="row" layout-align="space-between center">
<span><var:string label:value="Subscriptions"/></span>
<md-button class="sg-icon-button"
label:aria-label="Subscribe to a Calendar..."
sg-subscribe="calendar"
sg-subscribe-on-select="calendars.subscribeToFolder(folderData)">
sg-subscribe-on-select="app.subscribeToFolder(folderData)">
<md-icon>add_circle_outline</md-icon>
</md-button>
</div>
</md-subheader>
<md-list>
<md-list-item ng-repeat="calendar in calendars.service.$subscriptions">
<md-list-item ng-repeat="calendar in app.service.$subscriptions"
ng-dblclick="app.editFolder(calendar)">
<md-checkbox ng-model="calendar.active"
ng-class="calendar.getClassName('checkbox')"
ng-true-value="1"
ng-false-value="0"
label:aria-label="Enable"><!-- enable --></md-checkbox>
<p class="sg-item-name">{{calendar.name}}</p>
<md-menu class="md-secondary" label:aria-label="Options" ng-click="true">
<md-icon label:aria-label="Options"
<p class="sg-item-name" ng-show="app.editMode != calendar.id">
{{calendar.name}}
<span class="sg-counter-badge" ng-show="calendar.activeTasks">{{calendar.activeTasks}}</span>
</p>
<md-input-container class="md-flex"
ng-show="app.editMode == calendar.id">
<input class="sg-item-name" type="text"
label:aria-label="Name of the Calendar"
ng-model="calendar.name"
ng-blur="app.renameFolder(calendar)"
sg-focus-on="calendarName_{{calendar.id}}"
sg-enter="app.renameFolder(calendar)"
sg-escape="app.revertEditing(calendar)"/>
</md-input-container>
<md-menu class="md-secondary" label:aria-label="Options">
<md-button class="md-icon-button" label:aria-label="Options"
ng-click="$mdOpenMenu()"
md-menu-origin="md-menu-origin">more_vert</md-icon>
md-menu-origin="md-menu-origin">
<md-icon>more_vert</md-icon>
</md-button>
<md-menu-content width="2">
<md-menu-item>
<md-button ng-click="calendars.confirmDelete(calendar)">
<md-button type="button" ng-click="app.editFolder(calendar)">
<var:string label:value="Rename"/>
</md-button>
</md-menu-item>
<md-menu-item>
<md-button ng-click="app.confirmDelete(calendar)">
<var:string label:value="Unsubscribe Calendar"/>
</md-button>
</md-menu-item>
<md-menu-divider><!-- divider --></md-menu-divider>
<md-menu-item>
<md-button ng-click="calendars.showLinks(calendar)">
<md-button ng-click="app.showLinks(calendar)">
<var:string label:value="Links to this Calendar"/>
</md-button>
</md-menu-item>
<md-menu-divider><!-- divider --></md-menu-divider>
<md-menu-item>
<md-button ng-click="calendars.showProperties(calendar)">
<md-button ng-click="app.showProperties(calendar)">
<var:string label:value="Properties"/>
</md-button>
</md-menu-item>
@@ -258,44 +279,62 @@
</md-list>
</section>
<!-- Web Calendars -->
<section>
<md-subheader class="sg-md-subheader">
<section class="sg-section-list">
<md-subheader class="md-hue-2">
<div layout="row" layout-align="space-between center">
<span><var:string label:value="Web Calendars"/></span>
<md-button class="sg-icon-button"
label:aria-label="Subscribe to a web calendar..."
ng-click="calendars.addWebCalendar()">
ng-click="app.addWebCalendar()">
<md-icon>add_circle_outline</md-icon>
</md-button>
</div>
</md-subheader>
<md-list>
<md-list-item ng-repeat="calendar in calendars.service.$webcalendars">
<md-list-item ng-repeat="calendar in app.service.$webcalendars"
ng-dblclick="app.editFolder(calendar)">
<md-checkbox ng-model="calendar.active"
ng-class="calendar.getClassName('checkbox')"
ng-true-value="1"
ng-false-value="0"
label:aria-label="Enable"><!-- enable --></md-checkbox>
<p class="sg-item-name">{{calendar.name}}</p>
<md-menu class="md-secondary" label:aria-label="Options" ng-click="true">
<md-icon label:aria-label="Options"
ng-click="$mdOpenMenu()"
md-menu-origin="md-menu-origin">more_vert</md-icon>
<p class="sg-item-name" ng-show="app.editMode != calendar.id">{{calendar.name}}</p>
<md-input-container class="md-flex"
ng-show="app.editMode == calendar.id">
<input class="sg-item-name" type="text"
label:aria-label="Name of the Calendar"
ng-model="calendar.name"
ng-blur="app.renameFolder(calendar)"
sg-focus-on="calendarName_{{calendar.id}}"
sg-enter="app.renameFolder(calendar)"
sg-escape="app.revertEditing(calendar)"/>
</md-input-container>
<md-menu class="md-secondary" label:aria-label="Options">
<md-button class="md-icon-button" label:aria-label="Options"
ng-click="$mdOpenMenu()"
md-menu-origin="md-menu-origin">
<md-icon>more_vert</md-icon>
</md-button>
<md-menu-content width="2">
<md-menu-item>
<md-button ng-click="calendars.confirmDelete(calendar)">
<md-button type="button" ng-click="app.editFolder(calendar)">
<var:string label:value="Rename"/>
</md-button>
</md-menu-item>
<md-menu-item>
<md-button ng-click="app.confirmDelete(calendar)">
<var:string label:value="Delete"/>
</md-button>
</md-menu-item>
<md-menu-divider><!-- divider --></md-menu-divider>
<md-menu-item>
<md-button ng-click="calendars.showLinks(calendar)">
<md-button ng-click="app.showLinks(calendar)">
<var:string label:value="Links to this Calendar"/>
</md-button>
</md-menu-item>
<md-menu-divider><!-- divider --></md-menu-divider>
<md-menu-item>
<md-button ng-click="calendars.showProperties(calendar)">
<md-button ng-click="app.showProperties(calendar)">
<var:string label:value="Properties"/>
</md-button>
</md-menu-item>
@@ -310,197 +349,196 @@
<!-- Main section -->
<section layout="column" class="sg-app-content 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 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-toolbar layout="row" layout-align="space-between center" class="toolbar-main" >
<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> -->
</md-toolbar>
<div layout="row" class="md-flex">
<div class="view-list" layout="column">
<md-toolbar class="md-whiteframe-z1"
ng-show="list.component.$selectedCount() == 0">
<!-- sort/filter mode (default) -->
<div class="md-toolbar-tools" layout="row" ng-hide="list.mode.search">
<md-button class="sg-icon-button" label:aria-label="Search"
ng-click="list.mode.search = true">
<md-icon>search</md-icon>
</md-button>
</div> -->
</div><!-- .md-toolbar-tools -->
<div class="md-toolbar-tools" layout="row"
layout-align="space-between center"
ng-show="list.component.$selectedCount() == 0">
<!-- sort/filter mode -->
<div class="view-list" layout="row" layout-align="space-between center"
ng-hide="list.mode.search">
<div class="sg-toolbar-group">
<md-button class="sg-icon-button" label:aria-label="Search"
ng-click="list.mode.search = true">
<md-icon>search</md-icon>
<div class="md-flex"><!-- spacer --></div>
<md-menu>
<md-button class="sg-icon-button" label:aria-label="Filter"
ng-click="$mdOpenMenu()">
<md-icon>filter_list</md-icon>
</md-button>
</div>
<div class="sg-toolbar-group-last">
<md-menu>
<md-button class="sg-icon-button" label:aria-label="Filter"
ng-click="$mdOpenMenu()">
<md-icon>filter_list</md-icon>
</md-button>
<md-menu-content>
<md-menu-item>
<md-button ng-click="list.filter('view_all')">
<md-icon ng-class="{ 'icon-check': list.filteredBy('view_all') }">
<!-- selected --></md-icon> <var:string label:value="view_all"/>
</md-button>
</md-menu-item>
<md-menu-item>
<md-button ng-click="list.filter('view_today')">
<md-icon ng-class="{ 'icon-check': list.filteredBy('view_today') }">
<!-- selected --></md-icon> <var:string label:value="view_today"/>
</md-button>
</md-menu-item>
<md-menu-item>
<md-button ng-click="list.filter('view_next7')">
<md-icon ng-class="{ 'icon-check': list.filteredBy('view_next7') }">
<!-- selected --></md-icon> <var:string label:value="view_next7"/>
</md-button>
</md-menu-item>
<md-menu-item>
<md-button ng-click="list.filter('view_next14')">
<md-icon ng-class="{ 'icon-check': list.filteredBy('view_next14') }">
<!-- selected --></md-icon> <var:string label:value="view_next14"/>
</md-button>
</md-menu-item>
<md-menu-item>
<md-button ng-click="list.filter('view_next31')">
<md-icon ng-class="{ 'icon-check': list.filteredBy('view_next31') }">
<!-- selected --></md-icon><var:string label:value="view_next31"/>
</md-button>
</md-menu-item>
<md-menu-item>
<md-button ng-click="list.filter('view_thismonth')">
<md-icon ng-class="{ 'icon-check': list.filteredBy('view_thismonth') }">
<!-- selected --></md-icon><var:string label:value="view_thismonth"/>
</md-button>
</md-menu-item>
<md-menu-item ng-if="list.componentType == 'events'">
<md-button ng-click="list.filter('view_future')">
<md-icon ng-class="{ 'icon-check': list.component.$queryEvents.filterpopup == 'view_future' }">
<!-- selected --></md-icon> <var:string label:value="view_future"/>
</md-button>
</md-menu-item>
<md-menu-item ng-if="list.componentType == 'events'">
<md-button ng-click="list.filter('view_selectedday')">
<md-icon ng-class="{ 'icon-check': list.component.$queryEvents.filterpopup == 'view_selectedday' }">
<!-- selected --></md-icon> <var:string label:value="view_selectedday"/>
</md-button>
</md-menu-item>
<md-menu-item ng-if="list.componentType == 'tasks'">
<md-button ng-click="list.filter('view_not_started')">
<md-icon ng-class="{ 'icon-check': list.component.$queryTasks.filterpopup == 'view_not_started' }">
<!-- selected --></md-icon> <var:string label:value="view_not_started"/>
</md-button>
</md-menu-item>
<md-menu-item ng-if="list.componentType == 'tasks'">
<md-button ng-click="list.filter('view_overdue')">
<md-icon ng-class="{ 'icon-check': list.component.$queryTasks.filterpopup == 'view_overdue' }">
<!-- selected --></md-icon> <var:string label:value="view_overdue"/>
</md-button>
</md-menu-item>
<md-menu-item ng-if="list.componentType == 'tasks'">
<md-button ng-click="list.filter('view_incomplete')">
<md-icon ng-class="{ 'icon-check': list.component.$queryTasks.filterpopup == 'view_incomplete' }">
<!-- selected --></md-icon> <var:string label:value="view_incomplete"/>
</md-button>
</md-menu-item>
<md-menu-divider ng-if="list.componentType == 'tasks'"><!-- divider --></md-menu-divider>
<md-menu-item ng-if="list.componentType == 'tasks'">
<md-button ng-click="list.component.$filter(list.componentType)">
<md-checkbox
ng-model="list.component.$queryTasks.show_completed"
ng-true-value="1"
ng-false-value="0"> <var:string label:value="Show completed tasks"/></md-checkbox>
</md-button>
</md-menu-item>
</md-menu-content>
</md-menu>
<md-menu>
<md-button class="sg-icon-button" label:aria-label="Sort"
ng-click="$mdOpenMenu()">
<md-icon>sort</md-icon>
</md-button>
<md-menu-content>
<md-menu-item>
<md-button ng-click="list.sort('title')">
<md-icon ng-class="{ 'icon-check': list.sortedBy('title') }">
<!-- selected --></md-icon> <var:string label:value="Title"/>
</md-button>
</md-menu-item>
<md-menu-item>
<md-button ng-click="list.sort('location')">
<md-icon ng-class="{ 'icon-check': list.sortedBy('location') }">
<!-- selected --></md-icon> <var:string label:value="Location"/>
</md-button>
</md-menu-item>
<md-menu-item>
<md-button ng-click="list.sort('calendarName')">
<md-icon ng-class="{ 'icon-check': list.sortedBy('calendarName') }">
<!-- selected --></md-icon> <var:string label:value="Calendar"/>
</md-button>
</md-menu-item>
<md-menu-item ng-if="list.componentType == 'events'">
<md-button ng-click="list.sort('start')">
<md-icon ng-class="{ 'icon-check': list.sortedBy('start') }">
<!-- selected --></md-icon> <var:string label:value="Start"/>
</md-button>
</md-menu-item>
<md-menu-item ng-if="list.componentType == 'events'">
<md-button ng-click="list.sort('end')">
<md-icon ng-class="{ 'icon-check': list.sortedBy('end') }">
<!-- selected --></md-icon> <var:string label:value="End"/>
</md-button>
</md-menu-item>
<md-menu-item ng-if="list.componentType == 'tasks'">
<md-button ng-click="list.sort('end')">
<md-icon ng-class="{ 'icon-check': list.sortedBy('end') }">
<!-- selected --></md-icon> <var:string label:value="Due Date"/>
</md-button>
</md-menu-item>
<md-menu-item ng-if="list.componentType == 'tasks'">
<md-button ng-click="list.sort('priority')">
<md-icon ng-class="{ 'icon-check': list.sortedBy('priority') }">
<!-- selected --></md-icon> <var:string label:value="Priority"/>
</md-button>
</md-menu-item>
<md-menu-item ng-if="list.componentType == 'tasks'">
<md-button ng-click="list.sort('category')">
<md-icon ng-class="{ 'icon-check': list.sortedBy('category') }">
<!-- selected --></md-icon> <var:string label:value="Category"/>
</md-button>
</md-menu-item>
<md-menu-item ng-if="list.componentType == 'tasks'">
<md-button ng-click="list.sort('status')">
<md-icon ng-class="{ 'icon-check': list.sortedBy('status') }">
<!-- selected --></md-icon> <var:string label:value="Status"/>
</md-button>
</md-menu-item>
<md-menu-divider><!-- divider --></md-menu-divider>
<md-menu-item ng-if="list.componentType == 'events'">
<md-button ng-click="list.component.$filter(list.componentType)">
<md-checkbox
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-click="list.component.$filter(list.componentType)">
<md-checkbox
ng-model="list.component.$queryTasks.asc"
ng-true-value="0"
ng-false-value="1"><var:string label:value="Descending Order"/></md-checkbox>
</md-button>
</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-menu-content>
<md-menu-item>
<md-button ng-click="list.filter('view_all')">
<md-icon ng-class="{ 'icon-check': list.filteredBy('view_all') }">
<!-- selected --></md-icon> <var:string label:value="view_all"/>
</md-button>
</md-menu-item>
<md-menu-item>
<md-button ng-click="list.filter('view_today')">
<md-icon ng-class="{ 'icon-check': list.filteredBy('view_today') }">
<!-- selected --></md-icon> <var:string label:value="view_today"/>
</md-button>
</md-menu-item>
<md-menu-item>
<md-button ng-click="list.filter('view_next7')">
<md-icon ng-class="{ 'icon-check': list.filteredBy('view_next7') }">
<!-- selected --></md-icon> <var:string label:value="view_next7"/>
</md-button>
</md-menu-item>
<md-menu-item>
<md-button ng-click="list.filter('view_next14')">
<md-icon ng-class="{ 'icon-check': list.filteredBy('view_next14') }">
<!-- selected --></md-icon> <var:string label:value="view_next14"/>
</md-button>
</md-menu-item>
<md-menu-item>
<md-button ng-click="list.filter('view_next31')">
<md-icon ng-class="{ 'icon-check': list.filteredBy('view_next31') }">
<!-- selected --></md-icon><var:string label:value="view_next31"/>
</md-button>
</md-menu-item>
<md-menu-item>
<md-button ng-click="list.filter('view_thismonth')">
<md-icon ng-class="{ 'icon-check': list.filteredBy('view_thismonth') }">
<!-- selected --></md-icon><var:string label:value="view_thismonth"/>
</md-button>
</md-menu-item>
<md-menu-item ng-if="list.componentType == 'events'">
<md-button ng-click="list.filter('view_future')">
<md-icon ng-class="{ 'icon-check': list.component.$queryEvents.filterpopup == 'view_future' }">
<!-- selected --></md-icon> <var:string label:value="view_future"/>
</md-button>
</md-menu-item>
<md-menu-item ng-if="list.componentType == 'events'">
<md-button ng-click="list.filter('view_selectedday')">
<md-icon ng-class="{ 'icon-check': list.component.$queryEvents.filterpopup == 'view_selectedday' }">
<!-- selected --></md-icon> <var:string label:value="view_selectedday"/>
</md-button>
</md-menu-item>
<md-menu-item ng-if="list.componentType == 'tasks'">
<md-button ng-click="list.filter('view_not_started')">
<md-icon ng-class="{ 'icon-check': list.component.$queryTasks.filterpopup == 'view_not_started' }">
<!-- selected --></md-icon> <var:string label:value="view_not_started"/>
</md-button>
</md-menu-item>
<md-menu-item ng-if="list.componentType == 'tasks'">
<md-button ng-click="list.filter('view_overdue')">
<md-icon ng-class="{ 'icon-check': list.component.$queryTasks.filterpopup == 'view_overdue' }">
<!-- selected --></md-icon> <var:string label:value="view_overdue"/>
</md-button>
</md-menu-item>
<md-menu-item ng-if="list.componentType == 'tasks'">
<md-button ng-click="list.filter('view_incomplete')">
<md-icon ng-class="{ 'icon-check': list.component.$queryTasks.filterpopup == 'view_incomplete' }">
<!-- selected --></md-icon> <var:string label:value="view_incomplete"/>
</md-button>
</md-menu-item>
<md-menu-divider ng-if="list.componentType == 'tasks'"><!-- divider --></md-menu-divider>
<md-menu-item ng-if="list.componentType == 'tasks'">
<md-button ng-click="list.component.$filter(list.componentType)">
<md-checkbox
ng-model="list.component.$queryTasks.show_completed"
ng-true-value="1"
ng-false-value="0"> <var:string label:value="Show completed tasks"/></md-checkbox>
</md-button>
</md-menu-item>
</md-menu-content>
</md-menu>
<md-menu>
<md-button class="sg-icon-button" label:aria-label="Sort"
ng-click="$mdOpenMenu()">
<md-icon>sort</md-icon>
</md-button>
</div>
<md-menu-content>
<md-menu-item>
<md-button ng-click="list.sort('title')">
<md-icon ng-class="{ 'icon-check': list.sortedBy('title') }">
<!-- selected --></md-icon> <var:string label:value="Title"/>
</md-button>
</md-menu-item>
<md-menu-item>
<md-button ng-click="list.sort('location')">
<md-icon ng-class="{ 'icon-check': list.sortedBy('location') }">
<!-- selected --></md-icon> <var:string label:value="Location"/>
</md-button>
</md-menu-item>
<md-menu-item>
<md-button ng-click="list.sort('calendarName')">
<md-icon ng-class="{ 'icon-check': list.sortedBy('calendarName') }">
<!-- selected --></md-icon> <var:string label:value="Calendar"/>
</md-button>
</md-menu-item>
<md-menu-item ng-if="list.componentType == 'events'">
<md-button ng-click="list.sort('start')">
<md-icon ng-class="{ 'icon-check': list.sortedBy('start') }">
<!-- selected --></md-icon> <var:string label:value="Start"/>
</md-button>
</md-menu-item>
<md-menu-item ng-if="list.componentType == 'events'">
<md-button ng-click="list.sort('end')">
<md-icon ng-class="{ 'icon-check': list.sortedBy('end') }">
<!-- selected --></md-icon> <var:string label:value="End"/>
</md-button>
</md-menu-item>
<md-menu-item ng-if="list.componentType == 'tasks'">
<md-button ng-click="list.sort('end')">
<md-icon ng-class="{ 'icon-check': list.sortedBy('end') }">
<!-- selected --></md-icon> <var:string label:value="Due Date"/>
</md-button>
</md-menu-item>
<md-menu-item ng-if="list.componentType == 'tasks'">
<md-button ng-click="list.sort('priority')">
<md-icon ng-class="{ 'icon-check': list.sortedBy('priority') }">
<!-- selected --></md-icon> <var:string label:value="Priority"/>
</md-button>
</md-menu-item>
<md-menu-item ng-if="list.componentType == 'tasks'">
<md-button ng-click="list.sort('category')">
<md-icon ng-class="{ 'icon-check': list.sortedBy('category') }">
<!-- selected --></md-icon> <var:string label:value="Category"/>
</md-button>
</md-menu-item>
<md-menu-item ng-if="list.componentType == 'tasks'">
<md-button ng-click="list.sort('status')">
<md-icon ng-class="{ 'icon-check': list.sortedBy('status') }">
<!-- selected --></md-icon> <var:string label:value="Status"/>
</md-button>
</md-menu-item>
<md-menu-divider><!-- divider --></md-menu-divider>
<md-menu-item ng-if="list.componentType == 'events'">
<md-button ng-href="#">
<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-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>
</md-button>
</md-menu-item>
</md-menu-content>
</md-menu>
<md-button class="sg-icon-button" ng-click="list.reload()">
<md-icon>refresh</md-icon>
</md-button>
</div>
<!-- search mode -->
<div class="view-list sg-padded--right sg-toolbar-search" layout="row" layout-align="space-between center"
<div class="md-toolbar-tools sg-toolbar-secondary"
ng-show="list.mode.search"
sg-search="list.component.$filter(list.componentType, { value: searchText, search: searchField })">
<md-button class="sg-icon-button"
@@ -511,67 +549,73 @@
<md-input-container>
<input name="folderSearch" type="search" />
</md-input-container>
<md-input-container>
<md-input-container flex="25">
<md-select>
<md-option value="title_Category_Location" selected="selected"><var:string label:value="Title, category or location"/></md-option>
<md-option value="entireContent"><var:string label:value="Entire content"/></md-option>
</md-select>
</md-input-container>
</div>
<!-- day/week/month views -->
<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>
<a class="sg-icon-button md-button"
label:aria-label="Week"
href="#/calendar/week"><md-icon>view_week</md-icon></a>
<a class="sg-icon-button md-button"
label:aria-label="Month"
href="#/calendar/month"><md-icon>view_module</md-icon></a>
</md-toolbar>
<!-- multiple-selection mode -->
<md-toolbar class="md-whiteframe-z1 md-hue-1 sg-toolbar-secondary" ng-show="list.component.$selectedCount() > 0">
<div class="md-toolbar-tools">
<md-button class="sg-icon-button" ng-click="list.unselectComponents()">
<md-icon>arrow_back</md-icon>
</md-button>
<label>{{list.component.$selectedCount()}} <var:string label:value="selected"/></label>
<div class="md-flex"><!-- spacer --></div>
<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>
</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">
</md-toolbar>
<md-content layout="column" class="view-list">
<md-tabs md-dynamic-height="true"
md-selected="list.selectedList">
<!-- Events list -->
<md-tab label:label="Events"
md-on-select="list.selectComponentType('events')">
<md-subheader>
<md-button class="md-icon-button hide show-gt-sm" ng-click="toggleLeft()">
<md-icon ng-class="{'md-rotate-180': leftIsClose }">keyboard_arrow_left</md-icon>
</md-button>
<span>{{list.component.$queryEvents.filterpopup | loc}}</span>
</md-subheader>
<md-list class="sg-section-list">
<md-list-item class="md-2-line"
ng-repeat="event in list.component.$events"
<md-list-item 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">
<div class="md-avatar sg-avatar-selected" ng-show="event.selected"
ng-click="list.toggleComponentSelection($event, event)">
<!-- 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>
<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">
<md-icon ng-show="event.c_iscycle">repeat</md-icon>
<md-icon ng-show="event.c_nextalarm">alarm</md-icon>
</i>
</p>
<div class="sg-color-chip" ng-class="event.getClassName('bg')"
ng-show="!event.selected"
ng-click="list.toggleComponentSelection($event, event)"><!-- calendar color --></div>
<div class="sg-category"
ng-repeat="category in event.categories | limitTo:5"
ng-class="'bg-category' + category"
ng-style="{ left: ($index * 3) + 'px' }"><!-- calendar color --></div>
<div class="sg-tile-content">
<div class="sg-md-subhead">
<div>{{event.c_title}}</div>
</div>
<div class="sg-md-body">
<div>{{event.c_location}}</div>
<div class="sg-tile-date" ng-bind="event.formatted_startdate"><!-- start --></div>
</div>
</div>
<div class="sg-tile-icons">
<md-icon ng-show="event.c_iscycle">repeat</md-icon>
<md-icon ng-show="event.c_nextalarm">alarm</md-icon>
</div>
<md-divider><!-- divider --></md-divider>
</md-list-item>
<md-list-item disabled="disabled" ng-if="list.component.$events.length == 0">
<p class="sg-md-caption"><var:string label:value="No events for selected criteria"/></p>
@@ -581,25 +625,40 @@
<!-- Tasks list -->
<md-tab label:label="Tasks"
md-on-select="list.selectComponentType('tasks')">
<md-subheader>
<md-button class="md-icon-button hide show-gt-sm" ng-click="toggleLeft()">
<md-icon ng-class="{'md-rotate-180': leftIsClose }">keyboard_arrow_left</md-icon>
</md-button>
<span>{{list.component.$queryTasks.filterpopup | loc}}</span>
</md-subheader>
<md-list class="sg-section-list">
<md-list-item class="md-2-line"
ng-repeat="task in list.component.$tasks"
<md-list-item 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">
<div class="md-avatar sg-avatar-selected" ng-show="task.selected"
ng-click="list.toggleComponentSelection($event, task)">
<!-- 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>
<div class="md-list-item-text">
<h3>{{task.c_title}}</h3>
<p class="md-secondary" layout="row">
{{task.formatted_enddate}}
<span class="sg-tile-icons">
<md-icon ng-show="task.c_iscycle">repeat</md-icon>
<md-icon ng-show="event.c_nextalarm">alarm</md-icon>
</span>
</p>
<div class="sg-color-chip" ng-class="task.getClassName('bg')"
ng-show="!task.selected"
ng-click="list.toggleComponentSelection($event, task)"><!-- calendar color --></div>
<div class="sg-category"
ng-repeat="category in task.categories | limitTo:5"
ng-class="'bg-category' + category"
ng-style="{ left: ($index * 3) + 'px' }"><!-- calendar color --></div>
<div class="sg-tile-content">
<div class="sg-md-subhead">
<div>{{task.c_title}}</div>
</div>
<div class="sg-md-body">
<div><!-- spacer --></div>
<div>{{task.formatted_enddate}}</div>
</div>
</div>
<div class="sg-tile-icons">
<md-icon ng-show="task.c_iscycle">repeat</md-icon>
<md-icon ng-show="event.c_nextalarm">alarm</md-icon>
</div>
<md-divider><!-- divider --></md-divider>
</md-list-item>
<md-list-item disabled="disabled" ng-if="list.component.$tasks.length == 0">
<p class="sg-md-caption"><var:string label:value="No tasks for selected criteria"/></p>
@@ -608,17 +667,61 @@
</md-tab>
</md-tabs>
<md-button class="md-fab md-fab-bottom-right"
label:aria-label="New Appointment"
ng-click="list.newComponent($event)">
<md-icon>add</md-icon>
label:aria-label="Create a new event"
ng-click="list.newComponent($event)"
ng-if="list.componentType == 'events'">
<md-icon >event</md-icon>
</md-button>
<md-button class="md-fab md-fab-bottom-right"
label:aria-label="Create a new task"
ng-click="list.newComponent($event)"
ng-if="list.componentType == 'tasks'">
<md-icon>assignment_turned_in</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>
</div>
<div id="detailView" class="view-detail" hide-xs="hide-xs" layout="column" ui-view="calendarView">
<!-- calendar view -->
</div>
</div>
</section>
</script>
<script type="text/ng-template" id="UIxUserRightsEditor">
<var:component className="UIxCalUserRightsEditor" />
</script>
<!-- modal for calendar import -->
<script type="text/ng-template" id="UIxCalendarImportDialog">
<md-dialog flex="40" flex-sm="100" label:aria-label="Import Calendar">
<md-toolbar>
<div class="md-toolbar-tools">
<md-icon class="material-icons sg-icon-toolbar-bg">import_export</md-icon>
<div class="md-flex">
<div class="sg-md-title"><var:string label:value="Import Calendar"/></div>
</div>
<md-button class="md-icon-button" ng-click="$CalendarImportDialogController.close()">
<md-icon aria-label="Close dialog">close</md-icon>
</md-button>
</div>
</md-toolbar>
<md-dialog-content class="md-dialog-content">
<p><var:string label:value="Select an ICS file."/></p>
</md-dialog-content>
<md-dialog-actions>
<md-progress-circular class="md-accent"
md-mode="determinate"
md-diameter="20px"
ng-show="$CalendarImportDialogController.uploader.isUploading"
ng-value="$CalendarImportDialogController.uploader.progress"><!-- progress --></md-progress-circular>
<label class="md-button" for="file-input" ng-hide="$CalendarImportDialogController.uploader.isUploading">
<span><var:string label:value="Upload"/></span>
</label>
<input id="file-input" type="file" class="ng-hide"
nv-file-select="nv-file-select"
uploader="$CalendarImportDialogController.uploader"/>
</md-dialog-actions>
</md-dialog>
</script>
</var:component>
+94 -62
View File
@@ -1,71 +1,103 @@
<?xml version="1.0" standalone="yes"?>
<!DOCTYPE container>
<container
xmlns="http://www.w3.org/1999/xhtml"
xmlns:var="http://www.skyrix.com/od/binding"
xmlns:const="http://www.skyrix.com/od/constant"
xmlns:rsrc="OGo:url"
xmlns:label="OGo:label">
<container
xmlns="http://www.w3.org/1999/xhtml"
xmlns:var="http://www.skyrix.com/od/binding"
xmlns:const="http://www.skyrix.com/od/constant"
xmlns:rsrc="OGo:url"
xmlns:label="OGo:label">
<div class="menu" id="currentViewMenu" ng-hide="true">
<ul>
<li><var:string label:value="New Event..."/></li>
<li><var:string label:value="New Task..."/></li>
<li><!-- separator --></li>
<li><var:string label:value="Previous Month"/></li>
<li><var:string label:value="Next Month"/></li>
<li><!-- separator --></li>
<li><var:string label:value="Delete Event"/></li>
<li><var:string label:value="Copy event to my calendar"/></li>
<li><var:string label:value="View Raw Source"/></li>
</ul>
<md-toolbar class="md-whiteframe-z1" hide-sm="hide-sm">
<div class="md-toolbar-tools">
<md-button class="md-icon-button"
label:aria-label="Previous Month"
var:date="prevMonthQueryParameters.day"
ng-click="calendar.changeView($event)"><md-icon>chevron_left</md-icon></md-button>
<md-input-container>
<md-select ng-model="calendar.nav.month">
<md-option><var:string value="monthNameOfThisMonth" /></md-option>
</md-select>
</md-input-container>
<md-input-container>
<md-select ng-model="calendar.nav.year">
<md-option><var:string value="selectedDate.yearOfCommonEra" /></md-option>
</md-select>
</md-input-container>
<md-button class="md-icon-button"
label:aria-label="Next Month"
var:date="nextMonthQueryParameters.day"
ng-click="calendar.changeView($event)"><md-icon>chevron_right</md-icon></md-button>
<div class="md-flex"><!-- spacer --></div>
<md-button class="md-icon-button md-accent"
label:aria-label="Today"
ng-click="app.today()"><md-icon>today</md-icon></md-button>
<a class="md-icon-button md-button"
label:aria-label="Day"
href="#/calendar/day"><md-icon>view_day</md-icon></a>
<a class="md-icon-button md-button"
label:aria-label="Week"
href="#/calendar/week"><md-icon>view_week</md-icon></a>
<a class="md-icon-button md-button"
label:aria-label="Month"
ng-disabled="true"
href="#/calendar/month"><md-icon>view_module</md-icon></a>
<a class="md-icon-button md-button"
label:aria-label="Multicolumn Day View"
href="#/calendar/multicolumnday"><md-icon>view_array</md-icon></a>
</div>
</md-toolbar>
<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 class="monthView">
<div layout="row" layout-align="center center">
<var:foreach list="headerDaysToDisplay" item="currentTableDay">
<div class="md-flex-fix dayLabels"><var:string value="labelForCurrentDayToDisplay"/></div>
</var:foreach>
</div>
<md-grid-list
md-cols="7"
md-row-height="1:1">
<var:foreach list="weeksToDisplay" item="currentWeek">
<var:foreach list="currentWeek" item="currentTableDay">
<md-grid-tile
md-rowspan="1"
md-colspan="1"
class="day"
var:day="currentTableDay.shortDateString"
var:day-number="currentDayNumber"
var:id="currentDayId">
<div layout="column" layout-fill="true">
<div class="sg-calendar-tile-header"><var:string value="dayHeaderNumber"/></div>
<md-toolbar md-scroll-shrink="true" class="monthView md-hue-1">
<div layout="row" layout-align="center center"
class="md-flex md-default-theme md-fg md-hue-1">
<var:foreach list="headerDaysToDisplay" item="currentTableDay">
<div class="dayLabels"><var:string value="labelForCurrentDayToDisplay"/></div>
</var:foreach>
</div>
</md-toolbar>
<md-content class="md-flex" sg-calendar-scroll-view="monthly">
<div class="calendarView monthView">
<md-grid-list
md-cols="7"
md-row-height="1:1"
md-gutter="0">
<var:foreach list="weeksToDisplay" item="currentWeek">
<var:foreach list="currentWeek" item="currentTableDay">
<md-grid-tile
md-rowspan="1"
md-colspan="1"
var:class="dayCellClasses"
var:id="currentDayId"
>
<sg-calendar-day layout="column" layout-fill="true"
var:sg-day="currentTableDay.shortDateString"
var:sg-day-number="currentDayNumber"
var:sg-day-string="currentTableDay.iso8601DateString">
<div class="sg-calendar-tile-header md-default-theme md-fg md-hue-2">
<var:if condition="currentTableDay.isToday">
<span class="md-default-theme md-bg md-accent md-hue-2"><var:string value="currentTableDay.dayOfMonth"/></span> <var:string value="dayHeaderMonth"/>
</var:if>
<var:if condition="currentTableDay.isToday" const:negate="YES">
<span class=""><var:string value="currentTableDay.dayOfMonth"/></span> <var:string value="dayHeaderMonth"/>
</var:if>
</div>
<md-content
sg-draggable-calendar-block="sg-draggable-calendar-block"
class="clickableDayCell">
<sg-calendar-month-day
sg-blocks="calendar.blocks"
sg-blocks="calendar.views[0].blocks"
sg-click="list.openEvent(event, component)"
var:sg-day="currentTableDay.shortDateString"><!-- day's events --></sg-calendar-month-day>
</div>
</md-grid-tile>
</var:foreach>
</md-content>
<sg-calendar-month-event
sg-calendar-ghost="sg-calendar-ghost"
sg-block="list.component.$ghost"><!-- drag ghost --></sg-calendar-month-event>
</sg-calendar-day>
</md-grid-tile>
</var:foreach>
</md-grid-list>
</div>
</md-content>
</container>
</var:foreach>
</md-grid-list>
</div>
</md-content>
</container>
@@ -1,56 +1,46 @@
<?xml version="1.0" standalone="yes"?>
<container
<!DOCTYPE container>
<container
xmlns="http://www.w3.org/1999/xhtml"
xmlns:var="http://www.skyrix.com/od/binding"
xmlns:const="http://www.skyrix.com/od/constant"
xmlns:rsrc="OGo:url"
xmlns:label="OGo:label">
<div class="menu" id="currentViewMenu">
<ul>
<li><var:string label:value="New Event..."/></li>
<li><var:string label:value="New Task..."/></li>
<li><!-- separator --></li>
<li><var:string label:value="Previous Day"/></li>
<li><var:string label:value="Next Day"/></li>
<li><!-- separator --></li>
<li><var:string label:value="Delete Event"/></li>
<li><var:string label:value="Copy event to my calendar"/></li>
<li><var:string label:value="View Raw Source"/></li>
</ul>
<md-toolbar hide-sm="hide-sm">
<div class="md-toolbar-tools">
<md-button class="md-icon-button"
label:aria-label="Previous Day"
var:date="prevDayQueryParameters.day"
ng-click="calendar.changeView($event)"><md-icon>chevron_left</md-icon></md-button>
<div><var:string value="currentDayName" /></div>
<md-button class="md-icon-button"
label:aria-label="Next Day"
var:date="nextDayQueryParameters.day"
ng-click="calendar.changeView($event)"><md-icon>chevron_right</md-icon></md-button>
<div class="md-flex"><!-- spacer --></div>
<md-button class="md-icon-button md-accent"
label:aria-label="Today"
ng-click="app.today()"><md-icon>today</md-icon></md-button>
<a class="md-icon-button md-button"
label:aria-label="Day"
href="#/calendar/day"><md-icon>view_day</md-icon></a>
<a class="md-icon-button md-button"
label:aria-label="Week"
href="#/calendar/week"><md-icon>view_week</md-icon></a>
<a class="md-icon-button md-button"
label:aria-label="Month"
href="#/calendar/month"><md-icon>view_module</md-icon></a>
<a class="md-icon-button md-button"
label:aria-label="Multicolumn Day View"
ng-disabled="true"
href="#/calendar/multicolumnday"><md-icon>view_array</md-icon></a>
</div>
<!-- Navigation header -->
<span class="daysHeader">
<span class="day1">
<a href="#" id="leftNavigationArrow" var:date="prevDayQueryParameters.day" onclick="return onCalendarGotoDay(this);">
<img rsrc:src="arrow-left.png"/></a></span>
<span class="day0"><var:string value="currentDayName" /></span>
<span class="day1">
<a href="#" id="rightNavigationArrow" var:date="nextDayQueryParameters.day" onclick="return onCalendarGotoDay(this);">
<img rsrc:src="arrow-right.png"/></a></span>
<a href="#" id="listCollapse"><img var:class="collapseBtnClass" rsrc:src="collapse.png"/></a>
</span>
</md-toolbar>
<!-- TODO : Move this inside the schedulerUI.css -->
<style type="text/css">
DIV.day
{
width: <var:string value="dayWidthPercentage" />% !important;
}
<var:foreach list="subscriptionUsers" item="currentTableUser">
DIV[class~='day'].appointmentsOf<var:string value="currentTableUser" />
{
left: <var:string value="currentTableUserDayLeftPercentage" />% !important;
}
</var:foreach>
</style>
<!-- Display the calendar header and the table view -->
<div id="calendarContent">
<var:component
<var:component
className="UIxCalDayTable"
startDate="startDate"
const:CSSClass="dayOverview"
const:numberOfDays="1"
const:currentView="multicolumndayview"/>
</div>
</container>
</container>
@@ -1,16 +1,12 @@
<?xml version="1.0" standalone="yes"?>
<!DOCTYPE var:component>
<var:component xmlns="http://www.w3.org/1999/xhtml"
xmlns:var="http://www.skyrix.com/od/binding"
xmlns:const="http://www.skyrix.com/od/constant"
xmlns:uix="OGo:uix"
xmlns:label="OGo:label"
xmlns:rsrc="OGo:url"
className="UIxPageFrame"
title="title"
const:toolbar="none"
const:popup="YES">
<container
xmlns="http://www.w3.org/1999/xhtml"
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:uix="OGo:uix">
<div layout="column">
<md-input-container>
@@ -74,4 +70,4 @@
</div>
</var:component>
</container>
+45 -32
View File
@@ -1,34 +1,47 @@
<?xml version="1.0" standalone="yes"?>
<container
xmlns="http://www.w3.org/1999/xhtml"
xmlns:var="http://www.skyrix.com/od/binding"
xmlns:const="http://www.skyrix.com/od/constant"
xmlns:rsrc="OGo:url"
xmlns:label="OGo:label">
<!DOCTYPE container>
<container
xmlns="http://www.w3.org/1999/xhtml"
xmlns:var="http://www.skyrix.com/od/binding"
xmlns:const="http://www.skyrix.com/od/constant"
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>
</container>
<md-toolbar hide-sm="hide-sm">
<div class="md-toolbar-tools">
<md-button class="md-icon-button"
label:aria-label="Previous Week"
var:date="prevWeekQueryParameters.day"
ng-click="calendar.changeView($event)"><md-icon>chevron_left</md-icon></md-button>
<div><var:string value="currentWeekName" /></div>
<md-button class="md-icon-button"
label:aria-label="Next Week"
var:date="nextWeekQueryParameters.day"
ng-click="calendar.changeView($event)"><md-icon>chevron_right</md-icon></md-button>
<div class="md-flex"><!-- spacer --></div>
<md-button class="md-icon-button md-accent"
label:aria-label="Today"
ng-click="app.today()"><md-icon>today</md-icon></md-button>
<a class="md-icon-button md-button"
label:aria-label="Day"
href="#/calendar/day"><md-icon>view_day</md-icon></a>
<a class="md-icon-button md-button"
label:aria-label="Week"
ng-disabled="true"
href="#/calendar/week"><md-icon>view_week</md-icon></a>
<a class="md-icon-button md-button"
label:aria-label="Month"
href="#/calendar/month"><md-icon>view_module</md-icon></a>
<a class="md-icon-button md-button"
label:aria-label="Multicolumn Day View"
href="#/calendar/multicolumnday"><md-icon>view_array</md-icon></a>
</div>
</md-toolbar>
<var:component
className="UIxCalDayTable"
startDate="startDate"
const:CSSClass="weekOverview"
const:numberOfDays="7"
const:currentView="weekview"/>
</container>
@@ -8,7 +8,7 @@
>
<md-dialog flex="60" flex-sm="100">
<md-toolbar class="sg-padded">
<md-toolbar>
<md-icon class="material-icons sg-icon-toolbar-bg">link</md-icon>
<div class="md-toolbar-tools">
<div class="pseudo-input-container md-flex">
@@ -21,8 +21,8 @@
</div>
</md-toolbar>
<md-dialog-content>
<div layout="column" layout-padding="layout-padding">
<md-dialog-content class="md-padding">
<div layout="column">
<div layout="column" layout-padding="layout-padding">
<md-input-container ng-show="links.calendar.isWebCalendar">
@@ -8,10 +8,10 @@
>
<md-dialog flex-sm="100">
<md-toolbar ng-style="{ 'background-color': properties.calendar.color }">
<div class="md-toolbar-tools sg-padded--right">
<md-toolbar ng-class="properties.calendar.getClassName('bg')">
<div class="md-toolbar-tools">
<!-- color -->
<sg-color-picker sg-on-select="properties.calendar.color = color"><!-- color picker --></sg-color-picker>
<sg-color-picker ng-model="properties.calendar.color"><!-- color picker --></sg-color-picker>
<!-- name -->
<md-input-container>
<label><var:string label:value="Name"/></label>
@@ -25,7 +25,7 @@
</div>
</md-toolbar>
<md-dialog-content>
<md-dialog-content class="md-dialog-content" layout="column">
<md-checkbox
ng-model="properties.calendar.includeInFreeBusy"
ng-true-value="1"
@@ -44,6 +44,14 @@
ng-false-value="0">
<var:string label:value="Show tasks"/>
</md-checkbox>
<md-checkbox
ng-model="properties.calendar.synchronize"
ng-show="!properties.calendar.isWebCalendar"
ng-disabled="properties.calendar.id == 'personal'"
ng-true-value="1"
ng-false-value="0">
<var:string label:value="Synchronize"/>
</md-checkbox>
<md-checkbox
ng-model="properties.calendar.reloadOnLogin"
ng-show="properties.calendar.isWebCalendar"
@@ -51,7 +59,7 @@
ng-false-value="0">
<var:string label:value="Reload on login"/>
</md-checkbox>
<div ng-hide="properties.calendar.isWebCalendar || !properties.calendar.isOwned">
<div ng-hide="properties.calendar.isWebCalendar || !properties.calendar.isOwned" layout="column">
<md-divider><!-- divider --></md-divider>
<md-checkbox
ng-model="properties.calendar.notifications.notifyOnPersonalModifications"
@@ -80,10 +88,10 @@
</div>
</md-dialog-content>
<div class="md-actions">
<md-dialog-actions>
<md-button type="button" ng-click="properties.close()"><var:string label:value="Cancel"/></md-button>
<md-button ng-click="properties.saveProperties()"><var:string label:value="Save"/></md-button>
</div>
</md-dialog-actions>
</md-dialog>
</container>
+200 -176
View File
@@ -7,7 +7,7 @@
<md-dialog flex="60" flex-sm="100">
<form name="eventForm" ng-submit="editor.save(eventForm)">
<md-toolbar ng-class="editor.component.getClassName('bg')">
<div class="md-toolbar-tools sg-padded">
<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>
@@ -23,130 +23,155 @@
</md-button>
</div>
</md-toolbar>
<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>
<!-- categories -->
<md-chips ng-model="editor.component.categories">
<md-autocomplete
md-selected-item="editor.categories.selected"
md-search-text="editor.categories.searchText"
md-items="category in editor.component.constructor.filterCategories(editor.categories.searchText)"
label:placeholder="Add a category">
<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">
<md-radio-button value="public">
<var:string label:value="label_Public"/>
</md-radio-button>
<md-radio-button value="confidential">
<var:string label:value="label_Confidential"/>
</md-radio-button>
<md-radio-button value="private">
<var:string label:value="label_Private"/>
</md-radio-button>
</md-radio-group>
<!-- priority -->
<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"
step="1"
min="0"
max="9"
label:aria-label="Priority"><!-- slider --></md-slider>
</div>
<!-- is all day -->
<md-checkbox
ng-model="editor.component.isAllDay"
ng-true-value="1"
ng-false-value="0"
label:aria-label="All day Event">
<var:string label:value="All day Event"/>
</md-checkbox>
<!-- start + end -->
<div layout="row">
<md-dialog-content class="md-dialog-content">
<!-- location -->
<md-input-container>
<label><var:string label:value="Start"/></label>
<input type="text" ng-model="editor.component.startDate"/>
<label><var:string label:value="Location"/></label>
<input type="text" ng-model="editor.component.location"/>
</md-input-container>
<!-- categories -->
<md-chips ng-model="editor.component.categories">
<md-autocomplete
md-selected-item="editor.categories.selected"
md-search-text="editor.categories.searchText"
md-items="category in editor.component.constructor.filterCategories(editor.categories.searchText)"
md-min-length="0"
label:placeholder="Add a category">
<span md-highlight-text="editor.categories.searchText">{{category}}</span>
</md-autocomplete>
</md-chips>
<!-- calendar -->
<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">
<md-input-container flex="50">
<label><var:string label:value="Status"/></label>
<md-select ng-model="editor.component.status">
<var:foreach list="statusList" item="item">
<md-option var:value="item"><var:string value="itemStatusText"/></md-option>
</var:foreach>
<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>
<md-input-container ng-show="editor.component.status == 'completed'">
<label><var:string label:value="status_COMPLETED"/></label>
<input type="text" ng-model="editor.component.completedDate"/>
</md-input-container>
</div>
<div layout="row" layout-align="center center"
ng-show="editor.component.enablePercentComplete()">
<md-slider class="md-flex"
md-discrete="true"
ng-model="editor.component.percentComplete"
step="5"
min="0"
max="100"
label:aria-label="% complete"><!-- slider --></md-slider>
<div flex="30">{{editor.component.percentComplete}} <var:string label:value="% complete"/></div>
</div>
<!-- attach urls -->
<div class="attr" ng-repeat="attach in editor.component.attachUrls">
<div layout="row" layout-align="center end">
<md-input-container>
<label>
<var:string label:value="URL"/>
</label>
<input type="text" ng-model="attach.value"
sg-focus-on="attachUrl_{{$index}}"/>
</md-input-container>
<md-button class="sg-icon-button" type="button" ng-click="editor.component.deleteAttachUrl($index)">
<md-icon>remove_circle</md-icon>
</md-button>
<!-- classification -->
<md-radio-group layout="row" layout-align="space-around center"
ng-model="editor.component.classification">
<md-radio-button value="public">
<var:string label:value="label_Public"/>
</md-radio-button>
<md-radio-button value="confidential">
<var:string label:value="label_Confidential"/>
</md-radio-button>
<md-radio-button value="private">
<var:string label:value="label_Private"/>
</md-radio-button>
</md-radio-group>
<!-- priority -->
<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"
step="1"
min="0"
max="9"
label:aria-label="Priority"><!-- slider --></md-slider>
</div>
</div>
<div class="md-layout-margin" layout="row" layout-align="start center">
<md-button class="sg-icon-button" type="button" ng-click="editor.addAttachUrl($event)">
<md-icon>add_circle</md-icon>
</md-button>
<label class="button-label">
<var:string label:value="Attach"/>
</label>
</div>
<!-- comment -->
<md-input-container>
<label><var:string label:value="Description"/></label>
<textarea ng-model="editor.component.comment"><!-- comment --></textarea>
</md-input-container>
<!-- repeat -->
<div layout="row" layout-align="start end">
<div class="md-flex">
<!-- start -->
<div ng-show="editor.component.start">
<div class="pseudo-input-container">
<label class="pseudo-input-label"><var:string label:value="From"/></label>
</div>
<div layout="row" layout-align="start center" layout-wrap="layout-wrap">
<md-datepicker ng-model="editor.component.start"
ng-change="editor.updateStartTime()"
label:md-placeholder="From"> <!-- date picker--></md-datepicker>
<sg-timepicker ng-model="editor.component.start"
ng-change="editor.adjustStartTime()"><!-- time picker --></sg-timepicker>
<md-button class="md-icon-button" type="button" ng-click="editor.component.$deleteStartDate()">
<md-icon>remove_circle</md-icon>
</md-button>
</div>
</div>
<div class="md-layout-margin" layout="row" layout-align="start center" ng-hide="editor.component.start">
<md-button class="md-icon-button" type="button" ng-click="editor.addStartDate()">
<md-icon>add_circle</md-icon>
</md-button>
<label class="button-label"><var:string label:value="Add From"/></label>
</div>
<!-- due -->
<div ng-show="editor.component.due">
<div class="pseudo-input-container">
<label class="pseudo-input-label"><var:string label:value="Due"/></label>
</div>
<div layout="row" layout-align="start center" layout-wrap="layout-wrap">
<md-datepicker ng-model="editor.component.due"
ng-change="editor.updateDueTime()"
label:md-placeholder="Due"> <!-- date picker--></md-datepicker>
<sg-timepicker ng-model="editor.component.due"
ng-change="editor.adjustDueTime()"><!-- time picker --></sg-timepicker>
<md-button class="md-icon-button" type="button" ng-click="editor.component.$deleteDueDate()">
<md-icon>remove_circle</md-icon>
</md-button>
</div>
</div>
<div class="md-layout-margin" layout="row" layout-align="start center" ng-hide="editor.component.due">
<md-button class="md-icon-button" type="button" ng-click="editor.addDueDate()">
<md-icon>add_circle</md-icon>
</md-button>
<label class="button-label"><var:string label:value="Add Due"/></label>
</div>
<!-- status -->
<div layout="row">
<md-input-container flex="50">
<label><var:string label:value="Status"/></label>
<md-select ng-model="editor.component.status">
<var:foreach list="statusList" item="item">
<md-option var:value="item"><var:string value="itemStatusText"/></md-option>
</var:foreach>
</md-select>
</md-input-container>
<md-input-container ng-show="editor.component.status == 'completed'">
<label><var:string label:value="status_COMPLETED"/></label>
<input type="text" ng-model="editor.component.completedDate"/>
</md-input-container>
</div>
<div layout="row" layout-align="center center"
ng-show="editor.component.enablePercentComplete()">
<md-slider class="md-flex"
md-discrete="true"
ng-model="editor.component.percentComplete"
step="5"
min="0"
max="100"
label:aria-label="% complete"><!-- slider --></md-slider>
<div flex="30">{{editor.component.percentComplete}} <var:string label:value="% complete"/></div>
</div>
<!-- attach urls -->
<div class="attr" ng-repeat="attach in editor.component.attachUrls">
<div layout="row" layout-align="center end">
<md-input-container>
<label>
<var:string label:value="URL"/>
</label>
<input type="text" ng-model="attach.value"
sg-focus-on="attachUrl_{{$index}}"/>
</md-input-container>
<md-button class="md-icon-button" type="button" ng-click="editor.component.deleteAttachUrl($index)">
<md-icon>remove_circle</md-icon>
</md-button>
</div>
</div>
<div class="md-layout-margin" layout="row" layout-align="start center">
<md-button class="md-icon-button" type="button" ng-click="editor.addAttachUrl($event)">
<md-icon>add_circle</md-icon>
</md-button>
<label class="button-label">
<var:string label:value="Attach"/>
</label>
</div>
<!-- comment -->
<md-input-container>
<label><var:string label:value="Description"/></label>
<textarea ng-model="editor.component.comment"><!-- comment --></textarea>
</md-input-container>
<!-- repeat -->
<div layout="row" layout-align="start end">
<md-input-container>
<label><var:string label:value="Repeat"/></label>
<md-select class="pseudo-input-field" ng-model="editor.component.repeat.frequency">
@@ -155,63 +180,62 @@
</var:foreach>
</md-select>
</md-input-container>
<div class="md-flex"><!-- spacer --></div>
<md-button type="button" class="md-icon-button"
label:aria-label="repeat_CUSTOM"
ng-show="editor.component.repeat.frequency != 'never'"
ng-click="editor.toggleRecurrenceEditor()">
<md-icon ng-class="{'md-rotate-45': editor.showRecurrenceEditor}">add</md-icon>
</md-button>
</div>
<md-button type="button" class="sg-icon-button"
label:aria-label="repeat_CUSTOM"
ng-show="editor.component.repeat.frequency != 'never'"
ng-click="editor.toggleRecurrenceEditor()">
<md-icon ng-class="{'icon-more-horiz': !editor.showRecurrenceEditor,
'icon-clear': editor.showRecurrenceEditor}"><!-- toggle custom rule --></md-icon>
<div ng-show="editor.showRecurrenceEditor" class="sg-subcontent">
<var:component className="UIxRecurrenceEditor" />
</div>
<!-- end repeat -->
<div layout="row" layout-align="start end">
<div ng-show="editor.component.repeat.frequency != 'never'">
<md-input-container>
<label><var:string label:value="End Repeat"/></label>
<md-select class="pseudo-input-field" ng-model="editor.component.repeat.end">
<md-option value="never"><var:string label:value="Never"/></md-option>
<md-option value="count"><var:string label:value="After"/></md-option>
<md-option value="until"><var:string label:value="On Date"/></md-option>
</md-select>
</md-input-container>
</div>
<div layout="row" layout-align="start center" ng-show="editor.component.repeat.end == 'count'">
<md-input-container class="md-input-number">
<input type="number" label:aria-label="times" ng-model="editor.component.repeat.count"/>
</md-input-container>
<var:string label:value="times"/>
</div>
<md-input-container ng-show="editor.component.repeat.end == 'until'">
<input type="date" label:aria-label="Repeat until" ng-model="editor.component.repeat.until"/>
</md-input-container>
</div>
<!-- reminder -->
<md-checkbox ng-model="editor.component.$hasAlarm"
label:aria-label="Reminder">
<var:string label:value="Reminder"/>
</md-checkbox>
<div class="sg-subcontent"
ng-show="editor.component.$hasAlarm">
<var:component className="UIxReminderEditor" />
</div>
</md-dialog-content>
<!-- cancel/reset/save -->
<md-dialog-actions>
<md-button type="button" ng-click="editor.cancel()">
<var:string label:value="Cancel"/>
</md-button>
</div>
<div ng-show="editor.showRecurrenceEditor" class="sg-subcontent">
<var:component className="UIxRecurrenceEditor" />
</div>
<!-- end repeat -->
<div layout="row" layout-align="start end">
<div ng-show="editor.component.repeat.frequency != 'never'">
<md-input-container>
<label><var:string label:value="End Repeat"/></label>
<md-select class="pseudo-input-field" ng-model="editor.component.repeat.end">
<md-option value="never"><var:string label:value="Never"/></md-option>
<md-option value="count"><var:string label:value="After"/></md-option>
<md-option value="until"><var:string label:value="On Date"/></md-option>
</md-select>
</md-input-container>
</div>
<div layout="row" layout-align="start center" ng-show="editor.component.repeat.end == 'count'">
<md-input-container class="md-input-number">
<input type="number" label:aria-label="times" ng-model="editor.component.repeat.count"/>
</md-input-container>
<var:string label:value="times"/>
</div>
<md-input-container ng-show="editor.component.repeat.end == 'until'">
<input type="date" label:aria-label="Repeat until" ng-model="editor.component.repeat.until"/>
</md-input-container>
</div>
<!-- reminder -->
<md-checkbox ng-model="editor.component.$hasAlarm"
label:aria-label="Reminder">
<var:string label:value="Reminder"/>
</md-checkbox>
<div class="sg-subcontent"
ng-show="editor.component.$hasAlarm">
<var:component className="UIxReminderEditor" />
</div>
</md-dialog-content>
<!-- cancel/reset/save -->
<div class="md-actions">
<md-button type="button" ng-click="editor.cancel()">
<var:string label:value="Cancel"/>
</md-button>
<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">
<var:string label:value="Save"/>
</md-button>
</div>
</form>
</md-dialog>
<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">
<var:string label:value="Save"/>
</md-button>
</md-dialog-actions>
</form>
</md-dialog>
</container>
@@ -5,7 +5,7 @@
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-toolbar ng-class="editor.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">
@@ -13,12 +13,25 @@
<md-icon ng-if="editor.component.classification == 'confidential'">visibility_off</md-icon>
<md-icon ng-if="editor.component.classification == 'private'">vpn_key</md-icon>
<!-- summary -->
{{editor.component.summary}}
{{::editor.component.summary}}
<!-- priority -->
<md-icon ng-repeat="i in editor.component.priority | range">star</md-icon>
<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 aria-label="Close dialog">close</md-icon>
<md-menu>
<md-button label:aria-label="More options" class="sg-icon-button" ng-click="$mdOpenMenu($event)">
<md-icon>more_vert</md-icon>
</md-button>
<md-menu-content>
<md-menu-item>
<md-button label:aria-label="View Raw Source"
ng-click="editor.viewRawSource($event)">
<var:string label:value="View Raw Source"/>
</md-button>
</md-menu-item>
</md-menu-content>
</md-menu>
<md-button class="sg-icon-button" ng-click="editor.close()">
<md-icon label:aria-label="Close">close</md-icon>
</md-button>
</div>
</md-toolbar>
@@ -26,7 +39,7 @@
<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-chips class="sg-readonly" ng-model="::editor.component.categories" readonly="true">
<md-chip-template>
<span>{{$chip}}</span>
</md-chip-template>
@@ -35,7 +48,7 @@
<!-- location -->
<md-list-item ng-show="editor.component.location">
<md-icon>place</md-icon>
<p>{{editor.component.location}}</p>
<p>{{::editor.component.location}}</p>
</md-list-item>
<!-- calendar -->
<md-list-item>
@@ -43,23 +56,18 @@
<p>{{editor.component.calendar}}</p>
</md-list-item>
<!-- start/due dates -->
<md-list-item class="md-2-line">
<md-list-item ng-class="{ 'md-2-line': editor.component.isAllDay, 'md-3-line': !editor.component.isAllDay }"
ng-show="editor.component.startDate || editor.component.dueDate">
<md-icon>access_time</md-icon>
<div layout="row" class="md-flex">
<div class="md-list-item-text" ng-show="editor.component.startDate">
<p><var:string label:value="Start"/></p>
<h3>
{{editor.component.localizedStartDate}}
<span ng-hide="editor.component.isAllDay"> {{editor.component.localizedStartTime}}</span>
</h3>
</div>
<div class="md-list-item-text" ng-show="editor.component.dueDate">
<p><var:string label:value="Due Date"/></p>
<h3>
{{editor.component.localizedDueDate}}
<span ng-hide="editor.component.isAllDay">{{editor.component.localizedDueTime}}</span>
</h3>
</div>
<div class="md-list-item-text" ng-show="editor.component.startDate">
<p><var:string label:value="Start"/></p>
<h3>{{::editor.component.localizedStartDate}}</h3>
<h3 ng-hide="editor.component.isAllDay"> {{::editor.component.localizedStartTime}}</h3>
</div>
<div class="md-list-item-text" ng-show="editor.component.dueDate">
<p><var:string label:value="Due Date"/></p>
<h3>{{::editor.component.localizedDueDate}}</h3>
<h3 ng-hide="editor.component.isAllDay">{{::editor.component.localizedDueTime}}</h3>
</div>
</md-list-item>
<!-- status -->
@@ -72,32 +80,59 @@
<p>{{editor.component.percentComplete}} %</p>
</md-list-item>
<!-- attach urls -->
<md-list-item ng-repeat="url in editor.component.attachUrls">
<md-list-item ng-repeat="url in ::editor.component.attachUrls">
<md-icon>link</md-icon>
<p><a ng-href="url.value">{{url.value}}</a></p>
</md-list-item>
<!-- comment -->
<md-list-item ng-show="editor.component.comment">
<md-icon>mode_comment</md-icon>
<p>{{editor.component.comment}}</p>
<p>{{::editor.component.comment}}</p>
</md-list-item>
<!-- repeat -->
<md-list-item ng-show="editor.component.repeat">
<md-list-item ng-show="editor.component.$isRecurrent">
<md-icon>repeat</md-icon>
<p><!-- editor.component.repeat.toString() --></p>
<p>{{editor.component.repeatDescription()}}</p>
</md-list-item>
<!-- reminder -->
<md-list-item ng-show="editor.component.$hasAlarm">
<md-icon>alarm</md-icon>
<p><!-- editor.component.alarm.toString() --></p>
<md-icon>alarm_on</md-icon>
<p>{{editor.component.alarmDescription()}}</p>
</md-list-item>
</md-list>
</md-dialog-content>
<!-- edit -->
<div class="md-actions" ng-show="editor.component.isEditable()">
<md-dialog-actions ng-show="editor.component.isEditable()">
<md-button class="md-warn" label:aria-label="Delete Task"
ng-show="editor.component.isEditable() || editor.component.isInvitation()"
ng-click="editor.deleteAllOccurrences()">
<var:string label:value="Delete"/>
</md-button>
<md-menu ng-show="editor.component.isEditableOccurrence() || editor.component.isInvitationOccurrence()">
<md-button class="md-warn" label:aria-label="Delete Task"
ng-click="$mdOpenMenu()"
md-menu-origin="md-menu-origin">
<var:string label:value="Delete"/><md-icon>arrow_drop_down</md-icon>
</md-button>
<md-menu-content>
<md-menu-item>
<md-button class="md-warn"
ng-click="editor.deleteOccurrence()">
<var:string label:value="Delete This Occurrence"/>
</md-button>
</md-menu-item>
<md-menu-item>
<md-button class="md-warn"
ng-click="editor.deleteAllOccurrences()">
<var:string label:value="Delete All Occurrences"/>
</md-button>
</md-menu-item>
</md-menu-content>
</md-menu>
<div class="md-flex"><!-- spacer --></div>
<md-button ng-click="editor.edit()">
<var:string label:value="Edit"/>
</md-button>
</div>
</md-dialog-actions>
</md-dialog>
</container>
+44 -40
View File
@@ -7,7 +7,7 @@
xmlns:label="OGo:label"
>
<md-dialog flex="50" flex-sm="100">
<md-toolbar class="sg-padded">
<md-toolbar>
<div class="md-toolbar-tools">
<md-icon class="material-icons sg-icon-toolbar-bg">folder_shared</md-icon>
<div class="pseudo-input-container md-flex">
@@ -19,32 +19,59 @@
</md-button>
</div>
</md-toolbar>
<md-dialog-content>
<md-dialog-content class="md-padding">
<div layout="row">
<md-icon>search</md-icon>
<md-autocomplete
class="md-flex"
md-input-name="addUser"
md-search-text="acl.searchText"
md-selected-item="acl.userToAdd"
md-selected-item-change="acl.addUser(user)"
md-items="user in acl.userFilter(acl.searchText)"
md-item-text="user.empty"
md-min-length="3"
md-delay="300"
md-no-cache="true"
label:md-floating-label="Add User">
<md-item-template>
<span class="md-contact-suggestion">
<span class="md-contact-name"
md-highlight-text="acl.searchText"
md-highlight-flags="^i">{{user.cn}}</span>
<span class="md-contact-email"
md-highlight-text="acl.searchText"
md-highlight-flags="^i">{{user.c_email}}</span>
</span>
</md-item-template>
</md-autocomplete>
</div>
<md-card ng-repeat="user in acl.users | orderBy:['userClass', 'displayName']"
ng-class="{ 'sg-collapsed': user.uid != acl.selectedUser.uid, 'sg-expanded': user.uid == acl.selectedUser.uid }">
class="sg-collapsed"
ng-class="{ 'sg-expanded': user.uid == acl.selectedUid }">
<md-button ng-click="acl.selectUser(user)">
<div layout="row" layout-align="start center" class="md-flex">
<span class="card-picture" ng-switch="user.userClass">
<div ng-switch-when="normal-user">
<sg-avatar-image class="md-tile-left"
<sg-avatar-image class="md-avatar"
sg-email="user.c_email"
size="48"><!-- avatar --></sg-avatar-image>
size="40"><!-- avatar --></sg-avatar-image>
</div>
<div ng-switch-when="normal-group" class="sg-list-avatar"><!-- normal-group --></div>
<div ng-switch-when="public-user" class="sg-list-avatar"><!-- public-user --></div>
<div ng-switch-when="normal-group" class="md-avatar sg-avatar-list"><!-- normal-group --></div>
<div ng-switch-when="public-user" class="md-avatar sg-avatar-list"><!-- public-user --></div>
</span>
<div class="sg-tile-content">
<div class="sg-md-subhead-multi">{{user.cn}}</div>
<div class="sg-md-body-multi">{{user.c_email}}</div>
<div class="sg-md-subhead"><div>{{user.cn}}</div></div>
<div class="sg-md-body"><div>{{user.c_email}}</div></div>
</div>
<md-button class="sg-icon-button" type="button"
<md-button class="md-icon-button" type="button"
ng-click="acl.removeUser(user)"
ng-hide="user.uid != acl.selectedUser.uid || user.$isSpecial()">
ng-hide="user.uid != acl.selectedUid || user.$isSpecial()">
<md-icon>delete</md-icon>
</md-button>
</div>
</md-button>
<md-card-content id="AccessRightList" ng-show="user.uid == acl.selectedUser.uid">
<md-card-content id="AccessRightList" ng-show="user.uid == acl.selectedUid">
<var:if condition="canSubscribeUsers">
<md-checkbox ng-model="user.isSubscribed"
label:arial-label="Subscribe User"
@@ -67,33 +94,10 @@
</md-card>
</md-dialog-content>
<div ng-hide="acl.confirmation.showing" class="md-actions">
<md-autocomplete
class="md-flex"
md-input-name="addUser"
md-search-text="acl.searchText"
md-selected-item="acl.userToAdd"
md-selected-item-change="acl.addUser(user)"
md-items="user in acl.userFilter(acl.searchText)"
md-item-text="user.empty"
md-min-length="3"
md-delay="300"
md-no-cache="true"
label:md-floating-label="Add User">
<md-item-template>
<span class="md-contact-suggestion">
<span class="md-contact-name"
md-highlight-text="acl.searchText"
md-highlight-flags="^i">{{user.cn}}</span>
<span class="md-contact-email"
md-highlight-text="acl.searchText"
md-highlight-flags="^i">{{user.c_email}}</span>
</span>
</md-item-template>
</md-autocomplete>
<md-button ng-click="acl.saveModal()"><var:string label:value="Save"/></md-button>
</div>
<div class="md-actions" ng-show="acl.confirmation.showing">
<md-dialog-actions ng-hide="acl.confirmation.showing">
<md-button class="md-primary" ng-click="acl.saveModal()"><var:string label:value="Save"/></md-button>
</md-dialog-actions>
<md-dialog-actions ng-show="acl.confirmation.showing">
<span>{{acl.confirmation.message}}</span>
<md-button ng-click="acl.selectedUser.$resetRights(true); acl.confirmation.showing = false">
<var:string label:value="Cancel"/>
@@ -101,7 +105,7 @@
<md-button class="md-warn" ng-click="acl.confirmation.showing = false">
<var:string label:value="OK"/>
</md-button>
</div>
</md-dialog-actions>
</md-dialog>
</container>

Some files were not shown because too many files have changed in this diff Show More