Contacts tags support (unstable - step 1).

+ Small fixes
This commit is contained in:
RainLoop Team 2014-05-13 12:29:36 +04:00
parent 74fa12c000
commit 0ca00dec40
34 changed files with 1790 additions and 801 deletions

View file

@ -184,6 +184,7 @@ module.exports = function (grunt) {
"dev/Knoin/Knoin.js", "dev/Knoin/Knoin.js",
"dev/Models/EmailModel.js", "dev/Models/EmailModel.js",
"dev/Models/ContactTagModel.js",
"dev/ViewModels/PopupsDomainViewModel.js", "dev/ViewModels/PopupsDomainViewModel.js",
"dev/ViewModels/PopupsPluginViewModel.js", "dev/ViewModels/PopupsPluginViewModel.js",
@ -264,6 +265,7 @@ module.exports = function (grunt) {
"dev/Models/EmailModel.js", "dev/Models/EmailModel.js",
"dev/Models/ContactModel.js", "dev/Models/ContactModel.js",
"dev/Models/ContactPropertyModel.js", "dev/Models/ContactPropertyModel.js",
"dev/Models/ContactTagModel.js",
"dev/Models/AttachmentModel.js", "dev/Models/AttachmentModel.js",
"dev/Models/ComposeAttachmentModel.js", "dev/Models/ComposeAttachmentModel.js",
"dev/Models/MessageModel.js", "dev/Models/MessageModel.js",
@ -459,10 +461,10 @@ module.exports = function (grunt) {
require('wrench').rmdirSyncRecursive(releasesSrcPath); require('wrench').rmdirSyncRecursive(releasesSrcPath);
} }
}); });
// uglify // uglify
grunt.registerTask('rlmin', ['uglify:min_app', 'uglify:min_admin']); grunt.registerTask('rlmin', ['uglify:min_app', 'uglify:min_admin']);
// uglify (optional) // uglify (optional)
grunt.registerTask('rl', ['uglify:rl']); grunt.registerTask('rl', ['uglify:rl']);
grunt.registerTask('nano', ['uglify:nano']); grunt.registerTask('nano', ['uglify:nano']);

View file

@ -12,7 +12,7 @@ function RainLoopApp()
this.oRemote = null; this.oRemote = null;
this.oCache = null; this.oCache = null;
this.oMoveCache = {}; this.oMoveCache = {};
this.quotaDebounce = _.debounce(this.quota, 1000 * 30); this.quotaDebounce = _.debounce(this.quota, 1000 * 30);
this.moveOrDeleteResponseHelper = _.bind(this.moveOrDeleteResponseHelper, this); this.moveOrDeleteResponseHelper = _.bind(this.moveOrDeleteResponseHelper, this);
@ -189,11 +189,11 @@ RainLoopApp.prototype.contactsSync = function (fResultFunc)
{ {
return false; return false;
} }
oContacts.syncing(true); oContacts.syncing(true);
RL.remote().contactsSync(function (sResult, oData) { RL.remote().contactsSync(function (sResult, oData) {
oContacts.syncing(false); oContacts.syncing(false);
if (fResultFunc) if (fResultFunc)
@ -211,14 +211,14 @@ RainLoopApp.prototype.messagesMoveTrigger = function ()
self = this, self = this,
sSpamFolder = RL.data().spamFolder() sSpamFolder = RL.data().spamFolder()
; ;
_.each(this.oMoveCache, function (oItem) { _.each(this.oMoveCache, function (oItem) {
var var
bSpam = sSpamFolder === oItem['To'], bSpam = sSpamFolder === oItem['To'],
bHam = !bSpam && sSpamFolder === oItem['From'] && 'INBOX' === oItem['To'] bHam = !bSpam && sSpamFolder === oItem['From'] && 'INBOX' === oItem['To']
; ;
RL.remote().messagesMove(self.moveOrDeleteResponseHelper, oItem['From'], oItem['To'], oItem['Uid'], RL.remote().messagesMove(self.moveOrDeleteResponseHelper, oItem['From'], oItem['To'], oItem['Uid'],
bSpam ? 'SPAM' : (bHam ? 'HAM' : '')); bSpam ? 'SPAM' : (bHam ? 'HAM' : ''));
}); });
@ -272,7 +272,7 @@ RainLoopApp.prototype.moveOrDeleteResponseHelper = function (sResult, oData)
else else
{ {
RL.cache().setFolderHash(RL.data().currentFolderFullNameRaw(), ''); RL.cache().setFolderHash(RL.data().currentFolderFullNameRaw(), '');
if (oData && -1 < Utils.inArray(oData.ErrorCode, if (oData && -1 < Utils.inArray(oData.ErrorCode,
[Enums.Notification.CantMoveMessage, Enums.Notification.CantCopyMessage])) [Enums.Notification.CantMoveMessage, Enums.Notification.CantCopyMessage]))
{ {
@ -345,14 +345,14 @@ RainLoopApp.prototype.deleteMessagesFromFolder = function (iDeleteType, sFromFol
{ {
kn.showScreenPopup(PopupsFolderSystemViewModel, [nSetSystemFoldersNotification]); kn.showScreenPopup(PopupsFolderSystemViewModel, [nSetSystemFoldersNotification]);
} }
else if (!bUseFolder || (Enums.FolderType.Trash === iDeleteType && else if (!bUseFolder || (Enums.FolderType.Trash === iDeleteType &&
(sFromFolderFullNameRaw === oData.spamFolder() || sFromFolderFullNameRaw === oData.trashFolder()))) (sFromFolderFullNameRaw === oData.spamFolder() || sFromFolderFullNameRaw === oData.trashFolder())))
{ {
kn.showScreenPopup(PopupsAskViewModel, [Utils.i18n('POPUPS_ASK/DESC_WANT_DELETE_MESSAGES'), function () { kn.showScreenPopup(PopupsAskViewModel, [Utils.i18n('POPUPS_ASK/DESC_WANT_DELETE_MESSAGES'), function () {
self.messagesDeleteHelper(sFromFolderFullNameRaw, aUidForRemove); self.messagesDeleteHelper(sFromFolderFullNameRaw, aUidForRemove);
oData.removeMessagesFromList(sFromFolderFullNameRaw, aUidForRemove); oData.removeMessagesFromList(sFromFolderFullNameRaw, aUidForRemove);
}]); }]);
} }
else if (oMoveFolder) else if (oMoveFolder)
@ -469,7 +469,7 @@ RainLoopApp.prototype.reloadOpenPgpKeys = function ()
RainLoopApp.prototype.accountsAndIdentities = function () RainLoopApp.prototype.accountsAndIdentities = function ()
{ {
var oRainLoopData = RL.data(); var oRainLoopData = RL.data();
oRainLoopData.accountsLoading(true); oRainLoopData.accountsLoading(true);
oRainLoopData.identitiesLoading(true); oRainLoopData.identitiesLoading(true);
@ -477,14 +477,14 @@ RainLoopApp.prototype.accountsAndIdentities = function ()
oRainLoopData.accountsLoading(false); oRainLoopData.accountsLoading(false);
oRainLoopData.identitiesLoading(false); oRainLoopData.identitiesLoading(false);
if (Enums.StorageResultType.Success === sResult && oData.Result) if (Enums.StorageResultType.Success === sResult && oData.Result)
{ {
var var
sParentEmail = RL.settingsGet('ParentEmail'), sParentEmail = RL.settingsGet('ParentEmail'),
sAccountEmail = oRainLoopData.accountEmail() sAccountEmail = oRainLoopData.accountEmail()
; ;
sParentEmail = '' === sParentEmail ? sAccountEmail : sParentEmail; sParentEmail = '' === sParentEmail ? sAccountEmail : sParentEmail;
if (Utils.isArray(oData.Result['Accounts'])) if (Utils.isArray(oData.Result['Accounts']))
@ -493,21 +493,21 @@ RainLoopApp.prototype.accountsAndIdentities = function ()
return new AccountModel(sValue, sValue !== sParentEmail); return new AccountModel(sValue, sValue !== sParentEmail);
})); }));
} }
if (Utils.isArray(oData.Result['Identities'])) if (Utils.isArray(oData.Result['Identities']))
{ {
oRainLoopData.identities(_.map(oData.Result['Identities'], function (oIdentityData) { oRainLoopData.identities(_.map(oData.Result['Identities'], function (oIdentityData) {
var var
sId = Utils.pString(oIdentityData['Id']), sId = Utils.pString(oIdentityData['Id']),
sEmail = Utils.pString(oIdentityData['Email']), sEmail = Utils.pString(oIdentityData['Email']),
oIdentity = new IdentityModel(sId, sEmail, sId !== sAccountEmail) oIdentity = new IdentityModel(sId, sEmail, sId !== sAccountEmail)
; ;
oIdentity.name(Utils.pString(oIdentityData['Name'])); oIdentity.name(Utils.pString(oIdentityData['Name']));
oIdentity.replyTo(Utils.pString(oIdentityData['ReplyTo'])); oIdentity.replyTo(Utils.pString(oIdentityData['ReplyTo']));
oIdentity.bcc(Utils.pString(oIdentityData['Bcc'])); oIdentity.bcc(Utils.pString(oIdentityData['Bcc']));
return oIdentity; return oIdentity;
})); }));
} }
@ -518,7 +518,7 @@ RainLoopApp.prototype.accountsAndIdentities = function ()
RainLoopApp.prototype.quota = function () RainLoopApp.prototype.quota = function ()
{ {
this.remote().quota(function (sResult, oData) { this.remote().quota(function (sResult, oData) {
if (Enums.StorageResultType.Success === sResult && oData && oData.Result && if (Enums.StorageResultType.Success === sResult && oData && oData.Result &&
Utils.isArray(oData.Result) && 1 < oData.Result.length && Utils.isArray(oData.Result) && 1 < oData.Result.length &&
Utils.isPosNumeric(oData.Result[0], true) && Utils.isPosNumeric(oData.Result[1], true)) Utils.isPosNumeric(oData.Result[0], true) && Utils.isPosNumeric(oData.Result[1], true))
{ {
@ -555,7 +555,7 @@ RainLoopApp.prototype.folderInformation = function (sFolder, aList)
if (oFolder) if (oFolder)
{ {
oFolder.interval = iUtc; oFolder.interval = iUtc;
if (oData.Result.Hash) if (oData.Result.Hash)
{ {
RL.cache().setFolderHash(oData.Result.Folder, oData.Result.Hash); RL.cache().setFolderHash(oData.Result.Folder, oData.Result.Hash);
@ -652,7 +652,7 @@ RainLoopApp.prototype.folderInformationMultiply = function (bBoot)
if (oData && oData.Result && oData.Result.List && Utils.isNonEmptyArray(oData.Result.List)) if (oData && oData.Result && oData.Result.List && Utils.isNonEmptyArray(oData.Result.List))
{ {
_.each(oData.Result.List, function (oItem) { _.each(oData.Result.List, function (oItem) {
var var
aList = [], aList = [],
sHash = RL.cache().getFolderHash(oItem.Folder), sHash = RL.cache().getFolderHash(oItem.Folder),
@ -936,7 +936,7 @@ RainLoopApp.prototype.folderListOptionsBuilder = function (aSystem, aList, aDisa
} }
} }
} }
if (oItem.subScribed() && 0 < oItem.subFolders().length) if (oItem.subScribed() && 0 < oItem.subFolders().length)
{ {
aResult = aResult.concat(RL.folderListOptionsBuilder([], oItem.subFolders(), aDisabled, [], aResult = aResult.concat(RL.folderListOptionsBuilder([], oItem.subFolders(), aDisabled, [],
@ -970,10 +970,21 @@ RainLoopApp.prototype.getAutocomplete = function (sQuery, fCallback)
{ {
fCallback([]); fCallback([]);
} }
}, sQuery); }, sQuery);
}; };
/**
* @param {string} sQuery
* @param {Function} fCallback
*/
RainLoopApp.prototype.getContactsTagsAutocomplete = function (sQuery, fCallback)
{
fCallback(_.filter(RL.data().contactTags(), function (oContactTag) {
return oContactTag && oContactTag.filterHelper(sQuery);
}));
};
RainLoopApp.prototype.emailsPicsHashes = function () RainLoopApp.prototype.emailsPicsHashes = function ()
{ {
RL.remote().emailsPicsHashes(function (sResult, oData) { RL.remote().emailsPicsHashes(function (sResult, oData) {
@ -1021,7 +1032,7 @@ RainLoopApp.prototype.bootstart = function ()
bFacebook = RL.settingsGet('AllowFacebookSocial'), bFacebook = RL.settingsGet('AllowFacebookSocial'),
bTwitter = RL.settingsGet('AllowTwitterSocial') bTwitter = RL.settingsGet('AllowTwitterSocial')
; ;
if (!RL.settingsGet('ChangePasswordIsAllowed')) if (!RL.settingsGet('ChangePasswordIsAllowed'))
{ {
Utils.removeSettingsViewModel(SettingsChangePasswordScreen); Utils.removeSettingsViewModel(SettingsChangePasswordScreen);
@ -1036,7 +1047,7 @@ RainLoopApp.prototype.bootstart = function ()
{ {
Utils.removeSettingsViewModel(SettingsAccounts); Utils.removeSettingsViewModel(SettingsAccounts);
} }
if (RL.settingsGet('AllowIdentities')) if (RL.settingsGet('AllowIdentities'))
{ {
Utils.removeSettingsViewModel(SettingsIdentity); Utils.removeSettingsViewModel(SettingsIdentity);
@ -1045,7 +1056,7 @@ RainLoopApp.prototype.bootstart = function ()
{ {
Utils.removeSettingsViewModel(SettingsIdentities); Utils.removeSettingsViewModel(SettingsIdentities);
} }
if (!RL.settingsGet('OpenPGP')) if (!RL.settingsGet('OpenPGP'))
{ {
Utils.removeSettingsViewModel(SettingsOpenPGP); Utils.removeSettingsViewModel(SettingsOpenPGP);
@ -1060,12 +1071,12 @@ RainLoopApp.prototype.bootstart = function ()
{ {
Utils.removeSettingsViewModel(SettingsSocialScreen); Utils.removeSettingsViewModel(SettingsSocialScreen);
} }
if (!RL.settingsGet('AllowThemes')) if (!RL.settingsGet('AllowThemes'))
{ {
Utils.removeSettingsViewModel(SettingsThemes); Utils.removeSettingsViewModel(SettingsThemes);
} }
Utils.initOnStartOrLangChange(function () { Utils.initOnStartOrLangChange(function () {
$.extend(true, $.magnificPopup.defaults, { $.extend(true, $.magnificPopup.defaults, {
@ -1113,9 +1124,9 @@ RainLoopApp.prototype.bootstart = function ()
{ {
RL.data().openpgpKeyring = new window.openpgp.Keyring(); RL.data().openpgpKeyring = new window.openpgp.Keyring();
RL.data().allowOpenPGP(true); RL.data().allowOpenPGP(true);
RL.pub('openpgp.init'); RL.pub('openpgp.init');
RL.reloadOpenPgpKeys(); RL.reloadOpenPgpKeys();
} }
} }
@ -1127,7 +1138,7 @@ RainLoopApp.prototype.bootstart = function ()
} }
kn.startScreens([MailBoxScreen, SettingsScreen]); kn.startScreens([MailBoxScreen, SettingsScreen]);
if (bGoogle || bFacebook || bTwitter) if (bGoogle || bFacebook || bTwitter)
{ {
RL.socialUsers(true); RL.socialUsers(true);
@ -1163,7 +1174,7 @@ RainLoopApp.prototype.bootstart = function ()
window.setInterval(function () { window.setInterval(function () {
RL.contactsSync(); RL.contactsSync();
}, iContactsSyncInterval * 60000 + 5000); }, iContactsSyncInterval * 60000 + 5000);
_.delay(function () { _.delay(function () {
RL.contactsSync(); RL.contactsSync();
}, 5000); }, 5000);
@ -1223,7 +1234,7 @@ RainLoopApp.prototype.bootstart = function ()
Utils.initLayoutResizer('#rl-left', '#rl-right', Enums.ClientSideKeyName.FolderListSize); Utils.initLayoutResizer('#rl-left', '#rl-right', Enums.ClientSideKeyName.FolderListSize);
}); });
} }
}, this)); }, this));
} }
else else

View file

@ -74,7 +74,7 @@ ko.bindingHandlers.tooltip3 = {
'init': function (oElement) { 'init': function (oElement) {
var $oEl = $(oElement); var $oEl = $(oElement);
$oEl.tooltip({ $oEl.tooltip({
'container': 'body', 'container': 'body',
'trigger': 'hover manual', 'trigger': 'hover manual',
@ -93,7 +93,7 @@ ko.bindingHandlers.tooltip3 = {
$document.click(function () { $document.click(function () {
$oEl.tooltip('hide'); $oEl.tooltip('hide');
}); });
}, },
'update': function (oElement, fValueAccessor) { 'update': function (oElement, fValueAccessor) {
var sValue = ko.utils.unwrapObservable(fValueAccessor()); var sValue = ko.utils.unwrapObservable(fValueAccessor());
@ -124,7 +124,7 @@ ko.bindingHandlers.openDropdownTrigger = {
$el.find('.dropdown-toggle').dropdown('toggle'); $el.find('.dropdown-toggle').dropdown('toggle');
Utils.detectDropdownVisibility(); Utils.detectDropdownVisibility();
} }
fValueAccessor()(false); fValueAccessor()(false);
} }
} }
@ -221,7 +221,7 @@ ko.bindingHandlers.clickOnTrue = {
ko.bindingHandlers.modal = { ko.bindingHandlers.modal = {
'init': function (oElement, fValueAccessor) { 'init': function (oElement, fValueAccessor) {
$(oElement).toggleClass('fade', !Globals.bMobileDevice).modal({ $(oElement).toggleClass('fade', !Globals.bMobileDevice).modal({
'keyboard': false, 'keyboard': false,
'show': ko.utils.unwrapObservable(fValueAccessor()) 'show': ko.utils.unwrapObservable(fValueAccessor())
@ -536,11 +536,19 @@ ko.bindingHandlers.emailsTags = {
'init': function(oElement, fValueAccessor) { 'init': function(oElement, fValueAccessor) {
var var
$oEl = $(oElement), $oEl = $(oElement),
fValue = fValueAccessor() fValue = fValueAccessor(),
fFocusCallback = function (bValue) {
if (fValue && fValue.focusTrigger)
{
fValue.focusTrigger(bValue);
}
}
; ;
$oEl.inputosaurus({ $oEl.inputosaurus({
'parseOnBlur': true, 'parseOnBlur': true,
'allowDragAndDrop': true,
'focusCallback': fFocusCallback,
'inputDelimiters': [',', ';'], 'inputDelimiters': [',', ';'],
'autoCompleteSource': function (oData, fResponse) { 'autoCompleteSource': function (oData, fResponse) {
RL.getAutocomplete(oData.term, function (aData) { RL.getAutocomplete(oData.term, function (aData) {
@ -551,12 +559,12 @@ ko.bindingHandlers.emailsTags = {
}, },
'parseHook': function (aInput) { 'parseHook': function (aInput) {
return _.map(aInput, function (sInputValue) { return _.map(aInput, function (sInputValue) {
var var
sValue = Utils.trim(sInputValue), sValue = Utils.trim(sInputValue),
oEmail = null oEmail = null
; ;
if ('' !== sValue) if ('' !== sValue)
{ {
oEmail = new EmailModel(); oEmail = new EmailModel();
@ -586,8 +594,83 @@ ko.bindingHandlers.emailsTags = {
if (fValue.focusTrigger) if (fValue.focusTrigger)
{ {
fValue.focusTrigger.subscribe(function () { fValue.focusTrigger.subscribe(function (bValue) {
$oEl.inputosaurus('focus'); if (bValue)
{
$oEl.inputosaurus('focus');
}
});
}
}
};
ko.bindingHandlers.contactTags = {
'init': function(oElement, fValueAccessor) {
var
$oEl = $(oElement),
fValue = fValueAccessor(),
fFocusCallback = function (bValue) {
if (fValue && fValue.focusTrigger)
{
fValue.focusTrigger(bValue);
}
}
;
$oEl.inputosaurus({
'parseOnBlur': true,
'allowDragAndDrop': false,
'focusCallback': fFocusCallback,
'inputDelimiters': [';'],
'outputDelimiter': ';',
'autoCompleteSource': function (oData, fResponse) {
RL.getContactsTagsAutocomplete(oData.term, function (aData) {
fResponse(_.map(aData, function (oTagItem) {
return oTagItem.toLine(false);
}));
});
},
'parseHook': function (aInput) {
return _.map(aInput, function (sInputValue) {
var
sValue = Utils.trim(sInputValue),
oTag = null
;
if ('' !== sValue)
{
oTag = new ContactTagModel();
oTag.name(sValue);
return [oTag.toLine(false), oTag];
}
return [sValue, null];
});
},
'change': _.bind(function (oEvent) {
$oEl.data('ContactsTagsValue', oEvent.target.value);
fValue(oEvent.target.value);
}, this)
});
fValue.subscribe(function (sValue) {
if ($oEl.data('ContactsTagsValue') !== sValue)
{
$oEl.val(sValue);
$oEl.data('ContactsTagsValue', sValue);
$oEl.inputosaurus('refresh');
}
});
if (fValue.focusTrigger)
{
fValue.focusTrigger.subscribe(function (bValue) {
if (bValue)
{
$oEl.inputosaurus('focus');
}
}); });
} }
} }
@ -737,7 +820,7 @@ ko.observable.fn.validateFunc = function (fFunc)
this.subscribe(function (sValue) { this.subscribe(function (sValue) {
this.hasFuncError(!fFunc(sValue)); this.hasFuncError(!fFunc(sValue));
}, this); }, this);
this.valueHasMutated(); this.valueHasMutated();
} }

View file

@ -325,13 +325,13 @@ Utils.i18nToNode = function (oElement)
{ {
jqThis.html(Utils.i18n(sKey)); jqThis.html(Utils.i18n(sKey));
} }
sKey = jqThis.data('i18n-placeholder'); sKey = jqThis.data('i18n-placeholder');
if (sKey) if (sKey)
{ {
jqThis.attr('placeholder', Utils.i18n(sKey)); jqThis.attr('placeholder', Utils.i18n(sKey));
} }
sKey = jqThis.data('i18n-title'); sKey = jqThis.data('i18n-title');
if (sKey) if (sKey)
{ {
@ -469,7 +469,7 @@ Utils.fixLongSubject = function (sSubject)
; ;
sSubject = Utils.trim(sSubject.replace(/[\s]+/, ' ')); sSubject = Utils.trim(sSubject.replace(/[\s]+/, ' '));
do do
{ {
oMatch = /^Re(\[([\d]+)\]|):[\s]{0,3}Re(\[([\d]+)\]|):/ig.exec(sSubject); oMatch = /^Re(\[([\d]+)\]|):[\s]{0,3}Re(\[([\d]+)\]|):/ig.exec(sSubject);
@ -598,9 +598,9 @@ Utils.initNotificationLanguage = function ()
NotificationI18N[Enums.Notification.CantSaveSettings] = Utils.i18n('NOTIFICATIONS/CANT_SAVE_SETTINGS'); NotificationI18N[Enums.Notification.CantSaveSettings] = Utils.i18n('NOTIFICATIONS/CANT_SAVE_SETTINGS');
NotificationI18N[Enums.Notification.CantSavePluginSettings] = Utils.i18n('NOTIFICATIONS/CANT_SAVE_PLUGIN_SETTINGS'); NotificationI18N[Enums.Notification.CantSavePluginSettings] = Utils.i18n('NOTIFICATIONS/CANT_SAVE_PLUGIN_SETTINGS');
NotificationI18N[Enums.Notification.DomainAlreadyExists] = Utils.i18n('NOTIFICATIONS/DOMAIN_ALREADY_EXISTS'); NotificationI18N[Enums.Notification.DomainAlreadyExists] = Utils.i18n('NOTIFICATIONS/DOMAIN_ALREADY_EXISTS');
NotificationI18N[Enums.Notification.CantInstallPackage] = Utils.i18n('NOTIFICATIONS/CANT_INSTALL_PACKAGE'); NotificationI18N[Enums.Notification.CantInstallPackage] = Utils.i18n('NOTIFICATIONS/CANT_INSTALL_PACKAGE');
NotificationI18N[Enums.Notification.CantDeletePackage] = Utils.i18n('NOTIFICATIONS/CANT_DELETE_PACKAGE'); NotificationI18N[Enums.Notification.CantDeletePackage] = Utils.i18n('NOTIFICATIONS/CANT_DELETE_PACKAGE');
NotificationI18N[Enums.Notification.InvalidPluginPackage] = Utils.i18n('NOTIFICATIONS/INVALID_PLUGIN_PACKAGE'); NotificationI18N[Enums.Notification.InvalidPluginPackage] = Utils.i18n('NOTIFICATIONS/INVALID_PLUGIN_PACKAGE');
@ -613,7 +613,7 @@ Utils.initNotificationLanguage = function ()
NotificationI18N[Enums.Notification.DemoSendMessageError] = Utils.i18n('NOTIFICATIONS/DEMO_SEND_MESSAGE_ERROR'); NotificationI18N[Enums.Notification.DemoSendMessageError] = Utils.i18n('NOTIFICATIONS/DEMO_SEND_MESSAGE_ERROR');
NotificationI18N[Enums.Notification.AccountAlreadyExists] = Utils.i18n('NOTIFICATIONS/ACCOUNT_ALREADY_EXISTS'); NotificationI18N[Enums.Notification.AccountAlreadyExists] = Utils.i18n('NOTIFICATIONS/ACCOUNT_ALREADY_EXISTS');
NotificationI18N[Enums.Notification.MailServerError] = Utils.i18n('NOTIFICATIONS/MAIL_SERVER_ERROR'); NotificationI18N[Enums.Notification.MailServerError] = Utils.i18n('NOTIFICATIONS/MAIL_SERVER_ERROR');
NotificationI18N[Enums.Notification.UnknownNotification] = Utils.i18n('NOTIFICATIONS/UNKNOWN_ERROR'); NotificationI18N[Enums.Notification.UnknownNotification] = Utils.i18n('NOTIFICATIONS/UNKNOWN_ERROR');
NotificationI18N[Enums.Notification.UnknownError] = Utils.i18n('NOTIFICATIONS/UNKNOWN_ERROR'); NotificationI18N[Enums.Notification.UnknownError] = Utils.i18n('NOTIFICATIONS/UNKNOWN_ERROR');
@ -765,7 +765,7 @@ Utils.initDataConstructorBySettings = function (oData)
oData.contactsAutosave = ko.observable(false); oData.contactsAutosave = ko.observable(false);
Globals.sAnimationType = Enums.InterfaceAnimation.Full; Globals.sAnimationType = Enums.InterfaceAnimation.Full;
oData.allowThemes = ko.observable(true); oData.allowThemes = ko.observable(true);
oData.allowCustomLogin = ko.observable(false); oData.allowCustomLogin = ko.observable(false);
oData.allowLanguagesOnSettings = ko.observable(true); oData.allowLanguagesOnSettings = ko.observable(true);
@ -775,7 +775,7 @@ Utils.initDataConstructorBySettings = function (oData)
oData.useThreads = ko.observable(true); oData.useThreads = ko.observable(true);
oData.replySameFolder = ko.observable(true); oData.replySameFolder = ko.observable(true);
oData.useCheckboxesInList = ko.observable(true); oData.useCheckboxesInList = ko.observable(true);
oData.layout = ko.observable(Enums.Layout.SidePreview); oData.layout = ko.observable(Enums.Layout.SidePreview);
oData.usePreviewPane = ko.computed(function () { oData.usePreviewPane = ko.computed(function () {
return Enums.Layout.NoPreview !== oData.layout(); return Enums.Layout.NoPreview !== oData.layout();
@ -1058,7 +1058,7 @@ Utils.setExpandedFolder = function (sFullNameHash, bExpanded)
{ {
aExpandedList = []; aExpandedList = [];
} }
if (bExpanded) if (bExpanded)
{ {
aExpandedList.push(sFullNameHash); aExpandedList.push(sFullNameHash);
@ -1075,7 +1075,7 @@ Utils.setExpandedFolder = function (sFullNameHash, bExpanded)
Utils.initLayoutResizer = function (sLeft, sRight, sClientSideKeyName) Utils.initLayoutResizer = function (sLeft, sRight, sClientSideKeyName)
{ {
var var
iDisabledWidth = 65, iDisabledWidth = 60,
iMinWidth = 155, iMinWidth = 155,
oLeft = $(sLeft), oLeft = $(sLeft),
oRight = $(sRight), oRight = $(sRight),
@ -1153,7 +1153,7 @@ Utils.initBlockquoteSwitcher = function (oMessageTextBody)
var $oList = $('blockquote:not(.rl-bq-switcher)', oMessageTextBody).filter(function () { var $oList = $('blockquote:not(.rl-bq-switcher)', oMessageTextBody).filter(function () {
return 0 === $(this).parent().closest('blockquote', oMessageTextBody).length; return 0 === $(this).parent().closest('blockquote', oMessageTextBody).length;
}); });
if ($oList && 0 < $oList.length) if ($oList && 0 < $oList.length)
{ {
$oList.each(function () { $oList.each(function () {
@ -1563,7 +1563,7 @@ Utils.resizeAndCrop = function (sUrl, iValue, fCallback)
oCtx.fillStyle = '#fff'; oCtx.fillStyle = '#fff';
oCtx.fillRect(0, 0, iValue, iValue); oCtx.fillRect(0, 0, iValue, iValue);
oCtx.drawImage(this, aDiff[0] / 2, aDiff[1] / 2, this.width - aDiff[0], this.height - aDiff[1], 0, 0, iValue, iValue); oCtx.drawImage(this, aDiff[0] / 2, aDiff[1] / 2, this.width - aDiff[0], this.height - aDiff[1], 0, 0, iValue, iValue);
fCallback(oCanvas.toDataURL('image/jpeg')); fCallback(oCanvas.toDataURL('image/jpeg'));
}; };

View file

@ -17,7 +17,7 @@ function KnoinAbstractViewModel(sPosition, sTemplate)
this.viewModelName = ''; this.viewModelName = '';
this.viewModelVisibility = ko.observable(false); this.viewModelVisibility = ko.observable(false);
this.modalVisibility = ko.observable(false).extend({'rateLimit': 0}); this.modalVisibility = ko.observable(false).extend({'rateLimit': 0});
this.viewModelDom = null; this.viewModelDom = null;
} }
@ -72,14 +72,21 @@ KnoinAbstractViewModel.prototype.restoreKeyScope = function ()
RL.data().keyScope(this.sCurrentKeyScope); RL.data().keyScope(this.sCurrentKeyScope);
}; };
KnoinAbstractViewModel.prototype.registerPopupEscapeKey = function () KnoinAbstractViewModel.prototype.registerPopupKeyDown = function ()
{ {
var self = this; var self = this;
$window.on('keydown', function (oEvent) { $window.on('keydown', function (oEvent) {
if (oEvent && Enums.EventKeyCode.Esc === oEvent.keyCode && self.modalVisibility && self.modalVisibility()) if (oEvent && self.modalVisibility && self.modalVisibility())
{ {
Utils.delegateRun(self, 'cancelCommand'); if (!this.bDisabeCloseOnEsc && Enums.EventKeyCode.Esc === oEvent.keyCode)
return false; {
Utils.delegateRun(self, 'cancelCommand');
return false;
}
else if (Enums.EventKeyCode.Backspace === oEvent.keyCode && !Utils.inFocus())
{
return false;
}
} }
return true; return true;

View file

@ -83,7 +83,7 @@ Knoin.prototype.buildViewModel = function (ViewModelClass, oScreen)
ViewModelClass.__builded = true; ViewModelClass.__builded = true;
ViewModelClass.__vm = oViewModel; ViewModelClass.__vm = oViewModel;
oViewModel.data = RL.data(); oViewModel.data = RL.data();
oViewModel.viewModelName = ViewModelClass.__name; oViewModel.viewModelName = ViewModelClass.__name;
if (oViewModelPlace && 1 === oViewModelPlace.length) if (oViewModelPlace && 1 === oViewModelPlace.length)
@ -126,19 +126,19 @@ Knoin.prototype.buildViewModel = function (ViewModelClass, oScreen)
self.viewModelDom.hide(); self.viewModelDom.hide();
}, 300); }, 300);
} }
}, oViewModel); }, oViewModel);
} }
Plugins.runHook('view-model-pre-build', [ViewModelClass.__name, oViewModel, oViewModelDom]); Plugins.runHook('view-model-pre-build', [ViewModelClass.__name, oViewModel, oViewModelDom]);
ko.applyBindings(oViewModel, oViewModelDom[0]); ko.applyBindings(oViewModel, oViewModelDom[0]);
Utils.delegateRun(oViewModel, 'onBuild', [oViewModelDom]); Utils.delegateRun(oViewModel, 'onBuild', [oViewModelDom]);
if (oViewModel && 'Popups' === sPosition && !oViewModel.bDisabeCloseOnEsc) if (oViewModel && 'Popups' === sPosition)
{ {
oViewModel.registerPopupEscapeKey(); oViewModel.registerPopupKeyDown();
} }
Plugins.runHook('view-model-post-build', [ViewModelClass.__name, oViewModel, oViewModelDom]); Plugins.runHook('view-model-post-build', [ViewModelClass.__name, oViewModel, oViewModelDom]);
} }
else else
@ -240,7 +240,7 @@ Knoin.prototype.screenOnRoute = function (sScreenName, sSubPart)
} }
_.defer(function () { _.defer(function () {
// hide screen // hide screen
if (self.oCurrentScreen) if (self.oCurrentScreen)
{ {
@ -336,7 +336,7 @@ Knoin.prototype.startScreens = function (aScreensClasses)
{ {
oScreen.__started = true; oScreen.__started = true;
oScreen.__start(); oScreen.__start();
Plugins.runHook('screen-pre-start', [oScreen.screenName(), oScreen]); Plugins.runHook('screen-pre-start', [oScreen.screenName(), oScreen]);
Utils.delegateRun(oScreen, 'onStart'); Utils.delegateRun(oScreen, 'onStart');
Plugins.runHook('screen-post-start', [oScreen.screenName(), oScreen]); Plugins.runHook('screen-post-start', [oScreen.screenName(), oScreen]);

View file

@ -8,6 +8,7 @@ function ContactModel()
this.idContact = 0; this.idContact = 0;
this.display = ''; this.display = '';
this.properties = []; this.properties = [];
this.tags = '';
this.readOnly = false; this.readOnly = false;
this.focused = ko.observable(false); this.focused = ko.observable(false);
@ -21,11 +22,11 @@ function ContactModel()
*/ */
ContactModel.prototype.getNameAndEmailHelper = function () ContactModel.prototype.getNameAndEmailHelper = function ()
{ {
var var
sName = '', sName = '',
sEmail = '' sEmail = ''
; ;
if (Utils.isNonEmptyArray(this.properties)) if (Utils.isNonEmptyArray(this.properties))
{ {
_.each(this.properties, function (aProperty) { _.each(this.properties, function (aProperty) {
@ -58,6 +59,7 @@ ContactModel.prototype.parse = function (oItem)
this.idContact = Utils.pInt(oItem['IdContact']); this.idContact = Utils.pInt(oItem['IdContact']);
this.display = Utils.pString(oItem['Display']); this.display = Utils.pString(oItem['Display']);
this.readOnly = !!oItem['ReadOnly']; this.readOnly = !!oItem['ReadOnly'];
this.tags = '';
if (Utils.isNonEmptyArray(oItem['Properties'])) if (Utils.isNonEmptyArray(oItem['Properties']))
{ {
@ -69,6 +71,11 @@ ContactModel.prototype.parse = function (oItem)
}, this); }, this);
} }
if (Utils.isNonEmptyArray(oItem['Tags']))
{
this.tags = oItem['Tags'].join(';');
}
bResult = true; bResult = true;
} }

View file

@ -0,0 +1,45 @@
/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */
/**
* @constructor
*/
function ContactTagModel()
{
this.idContactTag = 0;
this.name = ko.observable('');
this.readOnly = false;
}
ContactTagModel.prototype.parse = function (oItem)
{
var bResult = false;
if (oItem && 'Object/Tag' === oItem['@Object'])
{
this.idContact = Utils.pInt(oItem['IdContactTag']);
this.name(Utils.pString(oItem['Name']));
this.readOnly = !!oItem['ReadOnly'];
bResult = true;
}
return bResult;
};
/**
* @param {string} sSearch
* @return {boolean}
*/
ContactTagModel.prototype.filterHelper = function (sSearch)
{
return this.name().toLowerCase().indexOf(sSearch.toLowerCase()) !== -1;
};
/**
* @param {boolean=} bEncodeHtml = false
* @return {string}
*/
ContactTagModel.prototype.toLine = function (bEncodeHtml)
{
return (Utils.isUnd(bEncodeHtml) ? false : !!bEncodeHtml) ?
Utils.encodeHtml(this.name()) : this.name();
};

View file

@ -7,7 +7,7 @@
function WebMailAjaxRemoteStorage() function WebMailAjaxRemoteStorage()
{ {
AbstractAjaxRemoteStorage.call(this); AbstractAjaxRemoteStorage.call(this);
this.oRequests = {}; this.oRequests = {};
} }
@ -686,11 +686,12 @@ WebMailAjaxRemoteStorage.prototype.contacts = function (fCallback, iOffset, iLim
/** /**
* @param {?Function} fCallback * @param {?Function} fCallback
*/ */
WebMailAjaxRemoteStorage.prototype.contactSave = function (fCallback, sRequestUid, sUid, aProperties) WebMailAjaxRemoteStorage.prototype.contactSave = function (fCallback, sRequestUid, sUid, sTags, aProperties)
{ {
this.defaultRequest(fCallback, 'ContactSave', { this.defaultRequest(fCallback, 'ContactSave', {
'RequestUid': sRequestUid, 'RequestUid': sRequestUid,
'Uid': Utils.trim(sUid), 'Uid': Utils.trim(sUid),
'Tags': Utils.trim(sTags),
'Properties': aProperties 'Properties': aProperties
}); });
}; };

View file

@ -83,13 +83,14 @@ function WebMailDataStorage()
this.identitiesLoading = ko.observable(false).extend({'throttle': 100}); this.identitiesLoading = ko.observable(false).extend({'throttle': 100});
// contacts // contacts
this.contactTags = ko.observableArray([]);
this.contacts = ko.observableArray([]); this.contacts = ko.observableArray([]);
this.contacts.loading = ko.observable(false).extend({'throttle': 200}); this.contacts.loading = ko.observable(false).extend({'throttle': 200});
this.contacts.importing = ko.observable(false).extend({'throttle': 200}); this.contacts.importing = ko.observable(false).extend({'throttle': 200});
this.contacts.syncing = ko.observable(false).extend({'throttle': 200}); this.contacts.syncing = ko.observable(false).extend({'throttle': 200});
this.contacts.exportingVcf = ko.observable(false).extend({'throttle': 200}); this.contacts.exportingVcf = ko.observable(false).extend({'throttle': 200});
this.contacts.exportingCsv = ko.observable(false).extend({'throttle': 200}); this.contacts.exportingCsv = ko.observable(false).extend({'throttle': 200});
this.allowContactsSync = ko.observable(false); this.allowContactsSync = ko.observable(false);
this.enableContactsSync = ko.observable(false); this.enableContactsSync = ko.observable(false);
this.contactsSyncUrl = ko.observable(''); this.contactsSyncUrl = ko.observable('');
@ -229,11 +230,11 @@ function WebMailDataStorage()
this.messageListEndFolder = ko.observable(''); this.messageListEndFolder = ko.observable('');
this.messageListEndSearch = ko.observable(''); this.messageListEndSearch = ko.observable('');
this.messageListEndPage = ko.observable(1); this.messageListEndPage = ko.observable(1);
this.messageListEndHash = ko.computed(function () { this.messageListEndHash = ko.computed(function () {
return this.messageListEndFolder() + '|' + this.messageListEndSearch() + '|' + this.messageListEndPage(); return this.messageListEndFolder() + '|' + this.messageListEndSearch() + '|' + this.messageListEndPage();
}, this); }, this);
this.messageListPageCount = ko.computed(function () { this.messageListPageCount = ko.computed(function () {
var iPage = Math.ceil(this.messageListCount() / this.messagesPerPage()); var iPage = Math.ceil(this.messageListCount() / this.messagesPerPage());
return 0 >= iPage ? 1 : iPage; return 0 >= iPage ? 1 : iPage;
@ -266,7 +267,7 @@ function WebMailDataStorage()
this.messageListCompleteLoading.subscribe(function (bValue) { this.messageListCompleteLoading.subscribe(function (bValue) {
this.messageListCompleteLoadingThrottle(bValue); this.messageListCompleteLoadingThrottle(bValue);
}, this); }, this);
this.messageList.subscribe(_.debounce(function (aList) { this.messageList.subscribe(_.debounce(function (aList) {
_.each(aList, function (oItem) { _.each(aList, function (oItem) {
if (oItem.newForAnimation()) if (oItem.newForAnimation())
@ -283,7 +284,7 @@ function WebMailDataStorage()
this.messageLoadingThrottle = ko.observable(false).extend({'throttle': 50}); this.messageLoadingThrottle = ko.observable(false).extend({'throttle': 50});
this.message.focused = ko.observable(false); this.message.focused = ko.observable(false);
this.message.subscribe(function (oMessage) { this.message.subscribe(function (oMessage) {
if (!oMessage) if (!oMessage)
{ {
@ -313,7 +314,7 @@ function WebMailDataStorage()
RL.data().keyScope(Enums.KeyState.MessageList); RL.data().keyScope(Enums.KeyState.MessageList);
} }
}); });
this.folderList.focused.subscribe(function (bValue) { this.folderList.focused.subscribe(function (bValue) {
if (bValue) if (bValue)
{ {
@ -324,11 +325,11 @@ function WebMailDataStorage()
RL.data().keyScope(Enums.KeyState.MessageList); RL.data().keyScope(Enums.KeyState.MessageList);
} }
}); });
this.messageLoading.subscribe(function (bValue) { this.messageLoading.subscribe(function (bValue) {
this.messageLoadingThrottle(bValue); this.messageLoadingThrottle(bValue);
}, this); }, this);
this.messageFullScreenMode = ko.observable(false); this.messageFullScreenMode = ko.observable(false);
this.messageError = ko.observable(''); this.messageError = ko.observable('');
@ -349,13 +350,13 @@ function WebMailDataStorage()
}, this); }, this);
this.currentMessage = ko.observable(null); this.currentMessage = ko.observable(null);
this.messageListChecked = ko.computed(function () { this.messageListChecked = ko.computed(function () {
return _.filter(this.messageList(), function (oItem) { return _.filter(this.messageList(), function (oItem) {
return oItem.checked(); return oItem.checked();
}); });
}, this).extend({'rateLimit': 0}); }, this).extend({'rateLimit': 0});
this.hasCheckedMessages = ko.computed(function () { this.hasCheckedMessages = ko.computed(function () {
return 0 < this.messageListChecked().length; return 0 < this.messageListChecked().length;
}, this).extend({'rateLimit': 0}); }, this).extend({'rateLimit': 0});
@ -442,7 +443,7 @@ WebMailDataStorage.prototype.purgeMessageBodyCache = function()
oMessagesBodiesDom = null, oMessagesBodiesDom = null,
iEnd = Globals.iMessageBodyCacheCount - Consts.Values.MessageBodyCacheLimit iEnd = Globals.iMessageBodyCacheCount - Consts.Values.MessageBodyCacheLimit
; ;
if (0 < iEnd) if (0 < iEnd)
{ {
oMessagesBodiesDom = this.messagesBodiesDom(); oMessagesBodiesDom = this.messagesBodiesDom();
@ -475,7 +476,7 @@ WebMailDataStorage.prototype.populateDataOnStart = function()
this.accountIncLogin(RL.settingsGet('IncLogin')); this.accountIncLogin(RL.settingsGet('IncLogin'));
this.accountOutLogin(RL.settingsGet('OutLogin')); this.accountOutLogin(RL.settingsGet('OutLogin'));
this.projectHash(RL.settingsGet('ProjectHash')); this.projectHash(RL.settingsGet('ProjectHash'));
this.displayName(RL.settingsGet('DisplayName')); this.displayName(RL.settingsGet('DisplayName'));
this.replyTo(RL.settingsGet('ReplyTo')); this.replyTo(RL.settingsGet('ReplyTo'));
this.signature(RL.settingsGet('Signature')); this.signature(RL.settingsGet('Signature'));
@ -517,7 +518,7 @@ WebMailDataStorage.prototype.initUidNextAndNewMessages = function (sFolder, sUid
{ {
oNotification.show(); oNotification.show();
} }
window.setTimeout((function (oLocalNotifications) { window.setTimeout((function (oLocalNotifications) {
return function () { return function () {
if (oLocalNotifications.cancel) if (oLocalNotifications.cancel)
@ -720,7 +721,7 @@ WebMailDataStorage.prototype.hideMessageBodies = function ()
WebMailDataStorage.prototype.getNextFolderNames = function (bBoot) WebMailDataStorage.prototype.getNextFolderNames = function (bBoot)
{ {
bBoot = Utils.isUnd(bBoot) ? false : !!bBoot; bBoot = Utils.isUnd(bBoot) ? false : !!bBoot;
var var
aResult = [], aResult = [],
iLimit = 10, iLimit = 10,
@ -756,10 +757,10 @@ WebMailDataStorage.prototype.getNextFolderNames = function (bBoot)
{ {
return 1; return 1;
} }
return 0; return 0;
}); });
_.find(aTimeouts, function (aItem) { _.find(aTimeouts, function (aItem) {
var oFolder = RL.cache().getFolderFromCacheList(aItem[1]); var oFolder = RL.cache().getFolderFromCacheList(aItem[1]);
if (oFolder) if (oFolder)
@ -767,7 +768,7 @@ WebMailDataStorage.prototype.getNextFolderNames = function (bBoot)
oFolder.interval = iUtc; oFolder.interval = iUtc;
aResult.push(aItem[1]); aResult.push(aItem[1]);
} }
return iLimit <= aResult.length; return iLimit <= aResult.length;
}); });
@ -785,7 +786,7 @@ WebMailDataStorage.prototype.removeMessagesFromList = function (
{ {
sToFolderFullNameRaw = Utils.isNormal(sToFolderFullNameRaw) ? sToFolderFullNameRaw : ''; sToFolderFullNameRaw = Utils.isNormal(sToFolderFullNameRaw) ? sToFolderFullNameRaw : '';
bCopy = Utils.isUnd(bCopy) ? false : !!bCopy; bCopy = Utils.isUnd(bCopy) ? false : !!bCopy;
aUidForRemove = _.map(aUidForRemove, function (mValue) { aUidForRemove = _.map(aUidForRemove, function (mValue) {
return Utils.pInt(mValue); return Utils.pInt(mValue);
}); });
@ -845,7 +846,7 @@ WebMailDataStorage.prototype.removeMessagesFromList = function (
else else
{ {
oData.messageListIsNotCompleted(true); oData.messageListIsNotCompleted(true);
_.each(aMessages, function (oMessage) { _.each(aMessages, function (oMessage) {
if (oCurrentMessage && oCurrentMessage.hash === oMessage.hash) if (oCurrentMessage && oCurrentMessage.hash === oMessage.hash)
{ {
@ -916,7 +917,7 @@ WebMailDataStorage.prototype.setMessage = function (oData, bCached)
oBody = $('<div id="' + sId + '" />').hide().addClass('rl-cache-class'); oBody = $('<div id="' + sId + '" />').hide().addClass('rl-cache-class');
oBody.data('rl-cache-count', ++Globals.iMessageBodyCacheCount); oBody.data('rl-cache-count', ++Globals.iMessageBodyCacheCount);
if (Utils.isNormal(oData.Result.Html) && '' !== oData.Result.Html) if (Utils.isNormal(oData.Result.Html) && '' !== oData.Result.Html)
{ {
bIsHtml = true; bIsHtml = true;
@ -926,7 +927,7 @@ WebMailDataStorage.prototype.setMessage = function (oData, bCached)
{ {
bIsHtml = false; bIsHtml = false;
sPlain = oData.Result.Plain.toString(); sPlain = oData.Result.Plain.toString();
if ((oMessage.isPgpSigned() || oMessage.isPgpEncrypted()) && if ((oMessage.isPgpSigned() || oMessage.isPgpEncrypted()) &&
RL.data().allowOpenPGP() && RL.data().allowOpenPGP() &&
Utils.isNormal(oData.Result.PlainRaw)) Utils.isNormal(oData.Result.PlainRaw))
@ -939,7 +940,7 @@ WebMailDataStorage.prototype.setMessage = function (oData, bCached)
bPgpSigned = /-----BEGIN PGP SIGNED MESSAGE-----/.test(oMessage.plainRaw) && bPgpSigned = /-----BEGIN PGP SIGNED MESSAGE-----/.test(oMessage.plainRaw) &&
/-----BEGIN PGP SIGNATURE-----/.test(oMessage.plainRaw); /-----BEGIN PGP SIGNATURE-----/.test(oMessage.plainRaw);
} }
$proxyDiv.empty(); $proxyDiv.empty();
if (bPgpSigned && oMessage.isPgpSigned()) if (bPgpSigned && oMessage.isPgpSigned())
{ {
@ -951,7 +952,7 @@ WebMailDataStorage.prototype.setMessage = function (oData, bCached)
} }
else if (bPgpEncrypted && oMessage.isPgpEncrypted()) else if (bPgpEncrypted && oMessage.isPgpEncrypted())
{ {
sPlain = sPlain =
$proxyDiv.append( $proxyDiv.append(
$('<pre class="b-plain-openpgp encrypted"></pre>').text(oMessage.plainRaw) $('<pre class="b-plain-openpgp encrypted"></pre>').text(oMessage.plainRaw)
).html() ).html()
@ -1028,7 +1029,7 @@ WebMailDataStorage.prototype.setMessage = function (oData, bCached)
{ {
RL.setMessageSeen(oMessage); RL.setMessageSeen(oMessage);
} }
Utils.windowResize(); Utils.windowResize();
} }
}; };
@ -1081,7 +1082,7 @@ WebMailDataStorage.prototype.setMessageList = function (oData, bCached)
if (oFolder && !bCached) if (oFolder && !bCached)
{ {
oFolder.interval = iUtc; oFolder.interval = iUtc;
RL.cache().setFolderHash(oData.Result.Folder, oData.Result.FolderHash); RL.cache().setFolderHash(oData.Result.Folder, oData.Result.FolderHash);
if (Utils.isNormal(oData.Result.MessageCount)) if (Utils.isNormal(oData.Result.MessageCount))

View file

@ -175,7 +175,7 @@
float: left; float: left;
padding: 0 8px 0 6px; padding: 0 8px 0 6px;
} }
.shareParent { .shareParent {
display: none; display: none;
float: right; float: right;
@ -224,7 +224,7 @@
} }
&.selected { &.selected {
background-color: #fff; background-color: #fff;
z-index: 102; z-index: 102;
@ -238,7 +238,7 @@
} }
} }
} }
.b-view-content-toolbar { .b-view-content-toolbar {
background-color: #f5f5f5; background-color: #f5f5f5;
padding: 7px; padding: 7px;
@ -279,6 +279,27 @@
-webkit-overflow-scrolling: touch; -webkit-overflow-scrolling: touch;
} }
.tags-property-container {
font-size: 18px;
width: 400px;
.inputosaurus-container {
border-width: 1px;
border-color: transparent;
.box-shadow(none);
&:hover {
.box-shadow(inset 0 1px 1px rgba(0, 0, 0, 0.075));
border-color: #ccc;
}
&.inputosaurus-focused {
.box-shadow(inset 0 1px 1px rgba(0, 0, 0, 0.075));
border-color: #999;
}
}
}
.contactValueStatic, .contactValueLargeStatic, .contactValueTextAreaStatic { .contactValueStatic, .contactValueLargeStatic, .contactValueTextAreaStatic {
height: 20px; height: 20px;
line-height: 20px; line-height: 20px;
@ -288,7 +309,7 @@
color: #555; color: #555;
display: none; display: none;
} }
&.read-only { &.read-only {
.contactValueStatic, .contactValueLargeStatic, .contactValueTextAreaStatic { .contactValueStatic, .contactValueLargeStatic, .contactValueTextAreaStatic {
display: inline-block; display: inline-block;
@ -361,7 +382,7 @@
color: #ddd; color: #ddd;
} }
} }
.contactValueTextArea { .contactValueTextArea {
width: 300px; width: 300px;
} }

View file

@ -175,9 +175,9 @@ html.ssm-state-tablet {
} }
html.rl-left-panel-disabled { html.rl-left-panel-disabled {
#rl-left { #rl-left {
width: 65px !important; width: 60px !important;
.show-on-panel-disabled { .show-on-panel-disabled {
display: block; display: block;
@ -201,7 +201,7 @@ html.rl-left-panel-disabled {
} }
#rl-right { #rl-right {
left: 65px !important; left: 60px !important;
} }
} }

View file

@ -1,14 +1,21 @@
.inputosaurus-container { .inputosaurus-container {
width: 99%; width: 99%;
line-height: 20px; line-height: 20px;
padding: 2px; padding: 2px;
border: 1px solid #cccccc; border: 1px solid #cccccc;
border-radius: 3px; border-radius: 3px;
.box-shadow(inset 0 1px 1px rgba(0, 0, 0, 0.075)); .box-shadow(inset 0 1px 1px rgba(0, 0, 0, 0.075));
.transition(~"border linear .2s, box-shadow linear .2s"); .transition(~"border linear .2s, box-shadow linear .2s");
&.inputosaurus-focused {
background-color: #fff;
border: @rlInputBorderSize solid darken(@inputBorder, 20%);
.box-shadow(none);
}
li { li {
max-width: 500px; max-width: 500px;
background-color: #eee; background-color: #eee;

View file

@ -67,9 +67,9 @@ function MailBoxMessageViewViewModel()
this.forwardCommand = createCommandHelper(Enums.ComposeType.Forward); this.forwardCommand = createCommandHelper(Enums.ComposeType.Forward);
this.forwardAsAttachmentCommand = createCommandHelper(Enums.ComposeType.ForwardAsAttachment); this.forwardAsAttachmentCommand = createCommandHelper(Enums.ComposeType.ForwardAsAttachment);
this.editAsNewCommand = createCommandHelper(Enums.ComposeType.EditAsNew); this.editAsNewCommand = createCommandHelper(Enums.ComposeType.EditAsNew);
this.messageVisibilityCommand = Utils.createCommand(this, Utils.emptyFunction, this.messageVisibility); this.messageVisibilityCommand = Utils.createCommand(this, Utils.emptyFunction, this.messageVisibility);
this.messageEditCommand = Utils.createCommand(this, function () { this.messageEditCommand = Utils.createCommand(this, function () {
this.editMessage(); this.editMessage();
}, this.messageVisibility); }, this.messageVisibility);
@ -91,7 +91,7 @@ function MailBoxMessageViewViewModel()
[this.message().uid], false); [this.message().uid], false);
} }
}, this.messageVisibility); }, this.messageVisibility);
this.archiveCommand = Utils.createCommand(this, function () { this.archiveCommand = Utils.createCommand(this, function () {
if (this.message()) if (this.message())
{ {
@ -100,7 +100,7 @@ function MailBoxMessageViewViewModel()
[this.message().uid], true); [this.message().uid], true);
} }
}, this.messageVisibility); }, this.messageVisibility);
this.spamCommand = Utils.createCommand(this, function () { this.spamCommand = Utils.createCommand(this, function () {
if (this.message()) if (this.message())
{ {
@ -120,6 +120,7 @@ function MailBoxMessageViewViewModel()
}, this.messageVisibility); }, this.messageVisibility);
// viewer // viewer
this.viewHash = '';
this.viewSubject = ko.observable(''); this.viewSubject = ko.observable('');
this.viewFromShort = ko.observable(''); this.viewFromShort = ko.observable('');
this.viewToShort = ko.observable(''); this.viewToShort = ko.observable('');
@ -134,7 +135,7 @@ function MailBoxMessageViewViewModel()
this.viewDownloadLink = ko.observable(''); this.viewDownloadLink = ko.observable('');
this.viewUserPic = ko.observable(Consts.DataImages.UserDotPic); this.viewUserPic = ko.observable(Consts.DataImages.UserDotPic);
this.viewUserPicVisible = ko.observable(false); this.viewUserPicVisible = ko.observable(false);
this.viewPgpPassword = ko.observable(''); this.viewPgpPassword = ko.observable('');
this.viewPgpSignedVerifyStatus = ko.computed(function () { this.viewPgpSignedVerifyStatus = ko.computed(function () {
return this.message() ? this.message().pgpSignedVerifyStatus() : Enums.SignedVerifyStatus.None; return this.message() ? this.message().pgpSignedVerifyStatus() : Enums.SignedVerifyStatus.None;
@ -143,7 +144,7 @@ function MailBoxMessageViewViewModel()
this.viewPgpSignedVerifyUser = ko.computed(function () { this.viewPgpSignedVerifyUser = ko.computed(function () {
return this.message() ? this.message().pgpSignedVerifyUser() : ''; return this.message() ? this.message().pgpSignedVerifyUser() : '';
}, this); }, this);
this.message.subscribe(function (oMessage) { this.message.subscribe(function (oMessage) {
this.messageActiveDom(null); this.messageActiveDom(null);
@ -152,6 +153,12 @@ function MailBoxMessageViewViewModel()
if (oMessage) if (oMessage)
{ {
if (this.viewHash !== oMessage.hash)
{
this.scrollMessageToTop();
}
this.viewHash = oMessage.hash;
this.viewSubject(oMessage.subject()); this.viewSubject(oMessage.subject());
this.viewFromShort(oMessage.fromToLine(true, true)); this.viewFromShort(oMessage.fromToLine(true, true));
this.viewToShort(oMessage.toToLine(true, true)); this.viewToShort(oMessage.toToLine(true, true));
@ -179,7 +186,12 @@ function MailBoxMessageViewViewModel()
} }
}); });
} }
else
{
this.viewHash = '';
this.scrollMessageToTop();
}
}, this); }, this);
this.fullScreenMode.subscribe(function (bValue) { this.fullScreenMode.subscribe(function (bValue) {
@ -202,14 +214,10 @@ function MailBoxMessageViewViewModel()
} }
}); });
this.messageActiveDom.subscribe(function () {
this.scrollMessageToTop();
}, this);
this.goUpCommand = Utils.createCommand(this, function () { this.goUpCommand = Utils.createCommand(this, function () {
RL.pub('mailbox.message-list.selector.go-up'); RL.pub('mailbox.message-list.selector.go-up');
}); });
this.goDownCommand = Utils.createCommand(this, function () { this.goDownCommand = Utils.createCommand(this, function () {
RL.pub('mailbox.message-list.selector.go-down'); RL.pub('mailbox.message-list.selector.go-down');
}); });
@ -274,7 +282,7 @@ MailBoxMessageViewViewModel.prototype.scrollToTop = function ()
// $('.messageItem', this.viewModelDom).animate({'scrollTop': 0}, 300); // $('.messageItem', this.viewModelDom).animate({'scrollTop': 0}, 300);
$('.messageItem', this.viewModelDom).scrollTop(0); $('.messageItem', this.viewModelDom).scrollTop(0);
} }
Utils.windowResize(); Utils.windowResize();
}; };
@ -308,7 +316,7 @@ MailBoxMessageViewViewModel.prototype.replyOrforward = function (sType)
MailBoxMessageViewViewModel.prototype.onBuild = function (oDom) MailBoxMessageViewViewModel.prototype.onBuild = function (oDom)
{ {
var var
self = this, self = this,
oData = RL.data() oData = RL.data()
; ;
@ -319,7 +327,7 @@ MailBoxMessageViewViewModel.prototype.onBuild = function (oDom)
self.message.focused(true); self.message.focused(true);
} }
}, this); }, this);
$('.attachmentsPlace', oDom).magnificPopup({ $('.attachmentsPlace', oDom).magnificPopup({
'delegate': '.magnificPopupImage:visible', 'delegate': '.magnificPopupImage:visible',
'type': 'image', 'type': 'image',
@ -513,7 +521,7 @@ MailBoxMessageViewViewModel.prototype.initShortcuts = function ()
{ {
self.message().printMessage(); self.message().printMessage();
} }
return false; return false;
}); });
@ -529,7 +537,7 @@ MailBoxMessageViewViewModel.prototype.initShortcuts = function ()
{ {
self.deleteCommand(); self.deleteCommand();
} }
return false; return false;
} }
}); });
@ -673,7 +681,7 @@ MailBoxMessageViewViewModel.prototype.readReceipt = function (oMessage)
if (oMessage && '' !== oMessage.readReceipt()) if (oMessage && '' !== oMessage.readReceipt())
{ {
RL.remote().sendReadReceiptMessage(Utils.emptyFunction, oMessage.folderFullNameRaw, oMessage.uid, RL.remote().sendReadReceiptMessage(Utils.emptyFunction, oMessage.folderFullNameRaw, oMessage.uid,
oMessage.readReceipt(), oMessage.readReceipt(),
Utils.i18n('READ_RECEIPT/SUBJECT', {'SUBJECT': oMessage.subject()}), Utils.i18n('READ_RECEIPT/SUBJECT', {'SUBJECT': oMessage.subject()}),
Utils.i18n('READ_RECEIPT/BODY', {'READ-RECEIPT': RL.data().accountEmail()})); Utils.i18n('READ_RECEIPT/BODY', {'READ-RECEIPT': RL.data().accountEmail()}));

View file

@ -24,7 +24,8 @@ function PopupsContactsViewModel()
this.search = ko.observable(''); this.search = ko.observable('');
this.contactsCount = ko.observable(0); this.contactsCount = ko.observable(0);
this.contacts = RL.data().contacts; this.contacts = RL.data().contacts;
this.contactTags = RL.data().contactTags;
this.currentContact = ko.observable(null); this.currentContact = ko.observable(null);
this.importUploaderButton = ko.observable(null); this.importUploaderButton = ko.observable(null);
@ -44,6 +45,21 @@ function PopupsContactsViewModel()
this.viewReadOnly = ko.observable(false); this.viewReadOnly = ko.observable(false);
this.viewProperties = ko.observableArray([]); this.viewProperties = ko.observableArray([]);
this.viewTags = ko.observable('');
this.viewTags.visibility = ko.observable(false);
this.viewTags.focusTrigger = ko.observable(false);
this.viewTags.focusTrigger.subscribe(function (bValue) {
if (!bValue && '' === this.viewTags())
{
this.viewTags.visibility(false);
}
else if (bValue)
{
this.viewTags.visibility(true);
}
}, this);
this.viewSaveTrigger = ko.observable(Enums.SaveSettingsStep.Idle); this.viewSaveTrigger = ko.observable(Enums.SaveSettingsStep.Idle);
this.viewPropertiesNames = this.viewProperties.filter(function(oProperty) { this.viewPropertiesNames = this.viewProperties.filter(function(oProperty) {
@ -57,7 +73,7 @@ function PopupsContactsViewModel()
Enums.ContactPropertyType.Note Enums.ContactPropertyType.Note
]); ]);
}); });
this.viewPropertiesOther = ko.computed(function () { this.viewPropertiesOther = ko.computed(function () {
var aList = _.filter(this.viewProperties(), function (oProperty) { var aList = _.filter(this.viewProperties(), function (oProperty) {
@ -71,7 +87,7 @@ function PopupsContactsViewModel()
}); });
}, this); }, this);
this.viewPropertiesEmails = this.viewProperties.filter(function(oProperty) { this.viewPropertiesEmails = this.viewProperties.filter(function(oProperty) {
return Enums.ContactPropertyType.Email === oProperty.type(); return Enums.ContactPropertyType.Email === oProperty.type();
}); });
@ -81,7 +97,7 @@ function PopupsContactsViewModel()
}); });
this.viewHasNonEmptyRequaredProperties = ko.computed(function() { this.viewHasNonEmptyRequaredProperties = ko.computed(function() {
var var
aNames = this.viewPropertiesNames(), aNames = this.viewPropertiesNames(),
aEmail = this.viewPropertiesEmails(), aEmail = this.viewPropertiesEmails(),
@ -89,7 +105,7 @@ function PopupsContactsViewModel()
return '' !== Utils.trim(oProperty.value()); return '' !== Utils.trim(oProperty.value());
} }
; ;
return !!(_.find(aNames, fHelper) || _.find(aEmail, fHelper)); return !!(_.find(aNames, fHelper) || _.find(aEmail, fHelper));
}, this); }, this);
@ -198,7 +214,7 @@ function PopupsContactsViewModel()
this.populateViewContact(null); this.populateViewContact(null);
this.currentContact(null); this.currentContact(null);
}); });
this.deleteCommand = Utils.createCommand(this, function () { this.deleteCommand = Utils.createCommand(this, function () {
this.deleteSelectedContacts(); this.deleteSelectedContacts();
this.emptySelection(true); this.emptySelection(true);
@ -213,7 +229,7 @@ function PopupsContactsViewModel()
aE = _.map(aC, function (oItem) { aE = _.map(aC, function (oItem) {
if (oItem) if (oItem)
{ {
var var
aData = oItem.getNameAndEmailHelper(), aData = oItem.getNameAndEmailHelper(),
oEmail = aData ? new EmailModel(aData[0], aData[1]) : null oEmail = aData ? new EmailModel(aData[0], aData[1]) : null
; ;
@ -235,7 +251,7 @@ function PopupsContactsViewModel()
kn.hideScreenPopup(PopupsContactsViewModel); kn.hideScreenPopup(PopupsContactsViewModel);
kn.showScreenPopup(PopupsComposeViewModel, [Enums.ComposeType.Empty, null, aE]); kn.showScreenPopup(PopupsComposeViewModel, [Enums.ComposeType.Empty, null, aE]);
} }
}, function () { }, function () {
return 0 < this.contactsCheckedOrSelected().length; return 0 < this.contactsCheckedOrSelected().length;
}); });
@ -245,11 +261,11 @@ function PopupsContactsViewModel()
}); });
this.saveCommand = Utils.createCommand(this, function () { this.saveCommand = Utils.createCommand(this, function () {
this.viewSaving(true); this.viewSaving(true);
this.viewSaveTrigger(Enums.SaveSettingsStep.Animate); this.viewSaveTrigger(Enums.SaveSettingsStep.Animate);
var var
sRequestUid = Utils.fakeMd5(), sRequestUid = Utils.fakeMd5(),
aProperties = [] aProperties = []
; ;
@ -265,7 +281,7 @@ function PopupsContactsViewModel()
var bRes = false; var bRes = false;
self.viewSaving(false); self.viewSaving(false);
if (Enums.StorageResultType.Success === sResult && oData && oData.Result && if (Enums.StorageResultType.Success === sResult && oData && oData.Result &&
oData.Result.RequestUid === sRequestUid && 0 < Utils.pInt(oData.Result.ResultID)) oData.Result.RequestUid === sRequestUid && 0 < Utils.pInt(oData.Result.ResultID))
{ {
@ -290,11 +306,11 @@ function PopupsContactsViewModel()
self.viewSaveTrigger(Enums.SaveSettingsStep.Idle); self.viewSaveTrigger(Enums.SaveSettingsStep.Idle);
}, 1000); }, 1000);
} }
}, sRequestUid, this.viewID(), aProperties); }, sRequestUid, this.viewID(), this.viewTags(), aProperties);
}, function () { }, function () {
var var
bV = this.viewHasNonEmptyRequaredProperties(), bV = this.viewHasNonEmptyRequaredProperties(),
bReadOnly = this.viewReadOnly() bReadOnly = this.viewReadOnly()
; ;
@ -313,7 +329,7 @@ function PopupsContactsViewModel()
self.reloadContactList(true); self.reloadContactList(true);
}); });
}, function () { }, function () {
return !this.contacts.syncing() && !this.contacts.importing(); return !this.contacts.syncing() && !this.contacts.importing();
}); });
@ -322,9 +338,9 @@ function PopupsContactsViewModel()
this.watchDirty = ko.observable(false); this.watchDirty = ko.observable(false);
this.watchHash = ko.observable(false); this.watchHash = ko.observable(false);
this.viewHash = ko.computed(function () { this.viewHash = ko.computed(function () {
return '' + _.map(self.viewProperties(), function (oItem) { return '' + self.viewTags() + '|' + _.map(self.viewProperties(), function (oItem) {
return oItem.value(); return oItem.value();
}).join(''); }).join('');
}); });
@ -385,6 +401,12 @@ PopupsContactsViewModel.prototype.addNewOrFocusProperty = function (sType, sType
} }
}; };
PopupsContactsViewModel.prototype.addNewTag = function ()
{
this.viewTags.visibility(true);
this.viewTags.focusTrigger(true);
};
PopupsContactsViewModel.prototype.addNewEmail = function () PopupsContactsViewModel.prototype.addNewEmail = function ()
{ {
this.addNewProperty(Enums.ContactPropertyType.Email, 'Home'); this.addNewProperty(Enums.ContactPropertyType.Email, 'Home');
@ -454,7 +476,7 @@ PopupsContactsViewModel.prototype.initUploader = function ()
this.contacts.importing(true); this.contacts.importing(true);
}, this)) }, this))
.on('onComplete', _.bind(function (sId, bResult, oData) { .on('onComplete', _.bind(function (sId, bResult, oData) {
this.contacts.importing(false); this.contacts.importing(false);
this.reloadContactList(); this.reloadContactList();
@ -478,7 +500,7 @@ PopupsContactsViewModel.prototype.removeCheckedOrSelectedContactsFromList = func
iCount = this.contacts().length, iCount = this.contacts().length,
aContacts = this.contactsCheckedOrSelected() aContacts = this.contactsCheckedOrSelected()
; ;
if (0 < aContacts.length) if (0 < aContacts.length)
{ {
_.each(aContacts, function (oContact) { _.each(aContacts, function (oContact) {
@ -499,11 +521,11 @@ PopupsContactsViewModel.prototype.removeCheckedOrSelectedContactsFromList = func
} }
_.delay(function () { _.delay(function () {
_.each(aContacts, function (oContact) { _.each(aContacts, function (oContact) {
oKoContacts.remove(oContact); oKoContacts.remove(oContact);
}); });
}, 500); }, 500);
} }
}; };
@ -562,7 +584,8 @@ PopupsContactsViewModel.prototype.populateViewContact = function (oContact)
this.emptySelection(false); this.emptySelection(false);
this.viewReadOnly(false); this.viewReadOnly(false);
this.viewTags('');
if (oContact) if (oContact)
{ {
sId = oContact.idContact; sId = oContact.idContact;
@ -587,15 +610,20 @@ PopupsContactsViewModel.prototype.populateViewContact = function (oContact)
}); });
} }
this.viewTags(oContact.tags);
this.viewReadOnly(!!oContact.readOnly); this.viewReadOnly(!!oContact.readOnly);
} }
this.viewTags.focusTrigger.valueHasMutated();
this.viewTags.visibility('' !== this.viewTags());
aList.unshift(new ContactPropertyModel(Enums.ContactPropertyType.LastName, '', sLastName, false, aList.unshift(new ContactPropertyModel(Enums.ContactPropertyType.LastName, '', sLastName, false,
this.getPropertyPlceholder(Enums.ContactPropertyType.LastName))); this.getPropertyPlceholder(Enums.ContactPropertyType.LastName)));
aList.unshift(new ContactPropertyModel(Enums.ContactPropertyType.FirstName, '', sFirstName, !oContact, aList.unshift(new ContactPropertyModel(Enums.ContactPropertyType.FirstName, '', sFirstName, !oContact,
this.getPropertyPlceholder(Enums.ContactPropertyType.FirstName))); this.getPropertyPlceholder(Enums.ContactPropertyType.FirstName)));
this.viewID(sId); this.viewID(sId);
this.viewProperties([]); this.viewProperties([]);
this.viewProperties(aList); this.viewProperties(aList);
@ -613,7 +641,7 @@ PopupsContactsViewModel.prototype.reloadContactList = function (bDropPagePositio
self = this, self = this,
iOffset = (this.contactsPage() - 1) * Consts.Defaults.ContactsPerPage iOffset = (this.contactsPage() - 1) * Consts.Defaults.ContactsPerPage
; ;
this.bDropPageAfterDelete = false; this.bDropPageAfterDelete = false;
if (Utils.isUnd(bDropPagePosition) ? false : !!bDropPagePosition) if (Utils.isUnd(bDropPagePosition) ? false : !!bDropPagePosition)
@ -626,9 +654,10 @@ PopupsContactsViewModel.prototype.reloadContactList = function (bDropPagePositio
RL.remote().contacts(function (sResult, oData) { RL.remote().contacts(function (sResult, oData) {
var var
iCount = 0, iCount = 0,
aList = [] aList = [],
aTagsList = []
; ;
if (Enums.StorageResultType.Success === sResult && oData && oData.Result && oData.Result.List) if (Enums.StorageResultType.Success === sResult && oData && oData.Result && oData.Result.List)
{ {
if (Utils.isNonEmptyArray(oData.Result.List)) if (Utils.isNonEmptyArray(oData.Result.List))
@ -643,14 +672,26 @@ PopupsContactsViewModel.prototype.reloadContactList = function (bDropPagePositio
iCount = Utils.pInt(oData.Result.Count); iCount = Utils.pInt(oData.Result.Count);
iCount = 0 < iCount ? iCount : 0; iCount = 0 < iCount ? iCount : 0;
} }
if (Utils.isNonEmptyArray(oData.Result.Tags))
{
aTagsList = _.map(oData.Result.Tags, function (oItem) {
var oContactTag = new ContactTagModel();
return oContactTag.parse(oItem) ? oContactTag : null;
});
aTagsList = _.compact(aTagsList);
}
} }
self.contactsCount(iCount); self.contactsCount(iCount);
self.contacts(aList); self.contacts(aList);
self.viewClearSearch('' !== self.search()); self.contactTags(aTagsList);
self.contacts.loading(false); self.contacts.loading(false);
self.viewClearSearch('' !== self.search());
}, iOffset, Consts.Defaults.ContactsPerPage, this.search()); }, iOffset, Consts.Defaults.ContactsPerPage, this.search());
}; };

File diff suppressed because it is too large Load diff

View file

@ -23,7 +23,7 @@ abstract class PdoAbstract
* @var string * @var string
*/ */
protected $sDbType; protected $sDbType;
/** /**
* @return bool * @return bool
*/ */
@ -67,7 +67,7 @@ abstract class PdoAbstract
{ {
return $this->oPDO; return $this->oPDO;
} }
if (!\class_exists('PDO')) if (!\class_exists('PDO'))
{ {
throw new \Exception('Class PDO does not exist'); throw new \Exception('Class PDO does not exist');
@ -100,7 +100,7 @@ abstract class PdoAbstract
{ {
throw $oException; throw $oException;
} }
if ($oPdo) if ($oPdo)
{ {
$this->oPDO = $oPdo; $this->oPDO = $oPdo;
@ -127,7 +127,7 @@ abstract class PdoAbstract
{ {
$mName = \strtolower($sTabelName.'_'.$sColumnName.'_seq'); $mName = \strtolower($sTabelName.'_'.$sColumnName.'_seq');
} }
return null === $mName ? $this->getPDO()->lastInsertId() : $this->getPDO()->lastInsertId($mName); return null === $mName ? $this->getPDO()->lastInsertId() : $this->getPDO()->lastInsertId($mName);
} }
@ -222,15 +222,15 @@ abstract class PdoAbstract
$mResult->closeCursor(); $mResult->closeCursor();
} }
} }
/** /**
* @param string $sSql * @param mixed $mData
*/ */
protected function writeLog($sSql) protected function writeLog($mData)
{ {
if ($this->oLogger) if ($this->oLogger)
{ {
$this->oLogger->WriteMixed($sSql, \MailSo\Log\Enumerations\Type::INFO, 'SQL'); $this->oLogger->WriteMixed($mData, \MailSo\Log\Enumerations\Type::INFO, 'SQL');
} }
} }
@ -324,7 +324,7 @@ abstract class PdoAbstract
} }
$this->writeLog($sQuery); $this->writeLog($sQuery);
$oStmt = $oPdo->prepare($sQuery); $oStmt = $oPdo->prepare($sQuery);
if ($oStmt->execute(array($sName))) if ($oStmt->execute(array($sName)))
{ {
@ -355,7 +355,7 @@ abstract class PdoAbstract
/** /**
* @param string $sName * @param string $sName
* @param int $iVersion * @param int $iVersion
* *
* @return bool * @return bool
*/ */
protected function setVersion($sName, $iVersion) protected function setVersion($sName, $iVersion)
@ -371,7 +371,7 @@ abstract class PdoAbstract
$sQuery = 'DELETE FROM rainloop_system WHERE sys_name = ? AND value_int <= ?;'; $sQuery = 'DELETE FROM rainloop_system WHERE sys_name = ? AND value_int <= ?;';
$this->writeLog($sQuery); $this->writeLog($sQuery);
$oStmt = $oPdo->prepare($sQuery); $oStmt = $oPdo->prepare($sQuery);
$bResult = !!$oStmt->execute(array($sName.'_version', $iVersion)); $bResult = !!$oStmt->execute(array($sName.'_version', $iVersion));
if ($bResult) if ($bResult)
@ -507,7 +507,7 @@ rl_email text NOT NULL DEFAULT \'\'
{ {
$oPdo->rollBack(); $oPdo->rollBack();
} }
throw $oException; throw $oException;
} }
} }
@ -550,7 +550,7 @@ rl_email text NOT NULL DEFAULT \'\'
{ {
$oPdo = false; $oPdo = false;
$bResult = false; $bResult = false;
foreach ($aData as $iVersion => $aQuery) foreach ($aData as $iVersion => $aQuery)
{ {
if (0 === \count($aQuery)) if (0 === \count($aQuery))
@ -580,7 +580,7 @@ rl_email text NOT NULL DEFAULT \'\'
if (false === $bExec) if (false === $bExec)
{ {
$this->writeLog('Result: false'); $this->writeLog('Result: false');
$bResult = false; $bResult = false;
break; break;
} }
@ -605,7 +605,7 @@ rl_email text NOT NULL DEFAULT \'\'
{ {
$oPdo->rollBack(); $oPdo->rollBack();
} }
throw $oException; throw $oException;
} }

View file

@ -85,7 +85,7 @@ class AddressBook extends \RainLoop\Providers\AbstractProvider
{ {
return $this->IsActive() ? $this->oDriver->Export($sEmail, $sType) : false; return $this->IsActive() ? $this->oDriver->Export($sEmail, $sType) : false;
} }
/** /**
* @param string $sEmail * @param string $sEmail
* @param \RainLoop\Providers\AddressBook\Classes\Contact $oContact * @param \RainLoop\Providers\AddressBook\Classes\Contact $oContact
@ -123,6 +123,16 @@ class AddressBook extends \RainLoop\Providers\AbstractProvider
$iOffset, $iLimit, $sSearch, $iResultCount) : array(); $iOffset, $iLimit, $sSearch, $iResultCount) : array();
} }
/**
* @param string $sEmail
*
* @return array
*/
public function GetContactTags($sEmail)
{
return $this->IsActive() ? $this->oDriver->GetContactTags($sEmail) : array();
}
/** /**
* @param string $sEmail * @param string $sEmail
* @param string $mID * @param string $mID
@ -238,7 +248,7 @@ class AddressBook extends \RainLoop\Providers\AbstractProvider
$aMap = \array_change_key_case($aMap, CASE_LOWER); $aMap = \array_change_key_case($aMap, CASE_LOWER);
} }
$sCsvNameLower = \MailSo\Base\Utils::IsAscii($sCsvName) ? \preg_replace('/[\s\-]+/', '', \strtolower($sCsvName)) : ''; $sCsvNameLower = \MailSo\Base\Utils::IsAscii($sCsvName) ? \preg_replace('/[\s\-]+/', '', \strtolower($sCsvName)) : '';
return !empty($sCsvNameLower) && isset($aMap[$sCsvNameLower]) ? $aMap[$sCsvNameLower] : PropertyType::UNKNOWN; return !empty($sCsvNameLower) && isset($aMap[$sCsvNameLower]) ? $aMap[$sCsvNameLower] : PropertyType::UNKNOWN;
} }
@ -258,7 +268,7 @@ class AddressBook extends \RainLoop\Providers\AbstractProvider
foreach ($aCsvData as $aItem) foreach ($aCsvData as $aItem)
{ {
\MailSo\Base\Utils::ResetTimeLimit(); \MailSo\Base\Utils::ResetTimeLimit();
foreach ($aItem as $sItemName => $sItemValue) foreach ($aItem as $sItemName => $sItemValue)
{ {
$sItemName = \trim($sItemName); $sItemName = \trim($sItemName);
@ -294,10 +304,10 @@ class AddressBook extends \RainLoop\Providers\AbstractProvider
unset($oContact); unset($oContact);
} }
return $iCount; return $iCount;
} }
/** /**
* @param string $sEmail * @param string $sEmail
* @param string $sVcfData * @param string $sVcfData
@ -336,14 +346,14 @@ class AddressBook extends \RainLoop\Providers\AbstractProvider
if ($oVCard instanceof \Sabre\VObject\Component\VCard) if ($oVCard instanceof \Sabre\VObject\Component\VCard)
{ {
\MailSo\Base\Utils::ResetTimeLimit(); \MailSo\Base\Utils::ResetTimeLimit();
if (empty($oVCard->UID)) if (empty($oVCard->UID))
{ {
$oVCard->UID = \Sabre\DAV\UUIDUtil::getUUID(); $oVCard->UID = \Sabre\DAV\UUIDUtil::getUUID();
} }
$oContact->PopulateByVCard($oVCard->serialize()); $oContact->PopulateByVCard($oVCard->serialize());
if (0 < \count($oContact->Properties)) if (0 < \count($oContact->Properties))
{ {
if ($this->ContactSave($sEmail, $oContact)) if ($this->ContactSave($sEmail, $oContact))

View file

@ -37,6 +37,11 @@ class Contact
/** /**
* @var array * @var array
*/ */
public $Tags;
/**
* @var bool
*/
public $ReadOnly; public $ReadOnly;
/** /**
@ -58,15 +63,15 @@ class Contact
{ {
$this->IdContact = ''; $this->IdContact = '';
$this->IdContactStr = ''; $this->IdContactStr = '';
$this->IdUser = 0;
$this->Display = ''; $this->Display = '';
$this->Changed = \time(); $this->Changed = \time();
$this->Properties = array(); $this->Properties = array();
$this->Tags = array();
$this->ReadOnly = false; $this->ReadOnly = false;
$this->IdPropertyFromSearch = 0; $this->IdPropertyFromSearch = 0;
$this->Etag = ''; $this->Etag = '';
} }
public function UpdateDependentValues() public function UpdateDependentValues()
{ {
$sLastName = ''; $sLastName = '';
@ -75,7 +80,7 @@ class Contact
$sOther = ''; $sOther = '';
$oFullNameProperty = null; $oFullNameProperty = null;
foreach ($this->Properties as /* @var $oProperty \RainLoop\Providers\AddressBook\Classes\Property */ &$oProperty) foreach ($this->Properties as /* @var $oProperty \RainLoop\Providers\AddressBook\Classes\Property */ &$oProperty)
{ {
if ($oProperty) if ($oProperty)
@ -133,7 +138,7 @@ class Contact
} }
$this->Display = \trim($sDisplay); $this->Display = \trim($sDisplay);
if ($oFullNameProperty) if ($oFullNameProperty)
{ {
$oFullNameProperty->Value = $this->Display; $oFullNameProperty->Value = $this->Display;
@ -200,7 +205,7 @@ class Contact
{ {
$oVCard = new \Sabre\VObject\Component\VCard(); $oVCard = new \Sabre\VObject\Component\VCard();
} }
$oVCard->VERSION = '3.0'; $oVCard->VERSION = '3.0';
$oVCard->PRODID = '-//RainLoop//'.APP_VERSION.'//EN'; $oVCard->PRODID = '-//RainLoop//'.APP_VERSION.'//EN';
@ -482,7 +487,7 @@ class Contact
public function PopulateByVCard($sVCard, $sEtag = '') public function PopulateByVCard($sVCard, $sEtag = '')
{ {
$this->Properties = array(); $this->Properties = array();
if (!empty($sEtag)) if (!empty($sEtag))
{ {
$this->Etag = $sEtag; $this->Etag = $sEtag;

View file

@ -0,0 +1,33 @@
<?php
namespace RainLoop\Providers\AddressBook\Classes;
class Tag
{
/**
* @var string
*/
public $IdContactTag;
/**
* @var string
*/
public $Name;
/**
* @var bool
*/
public $ReadOnly;
public function __construct()
{
$this->Clear();
}
public function Clear()
{
$this->IdContactTag = '';
$this->Name = '';
$this->ReadOnly = false;
}
}

View file

@ -17,7 +17,7 @@ class PdoAddressBook
* @var string * @var string
*/ */
private $sDsnType; private $sDsnType;
/** /**
* @var string * @var string
*/ */
@ -73,7 +73,7 @@ class PdoAddressBook
) )
); );
} }
private function prepearDatabaseSyncData($iUserID) private function prepearDatabaseSyncData($iUserID)
{ {
$aResult = array(); $aResult = array();
@ -122,7 +122,7 @@ class PdoAddressBook
{ {
$this->oLogger->WriteException($oException); $this->oLogger->WriteException($oException);
} }
if (\is_array($aResponse)) if (\is_array($aResponse))
{ {
$mResult = array(); $mResult = array();
@ -159,7 +159,7 @@ class PdoAddressBook
private function davClientRequest($oClient, $sCmd, $sUrl, $mData = null) private function davClientRequest($oClient, $sCmd, $sUrl, $mData = null)
{ {
\MailSo\Base\Utils::ResetTimeLimit(); \MailSo\Base\Utils::ResetTimeLimit();
$this->oLogger->Write($sCmd.' '.$sUrl.('PUT' === $sCmd && null !== $mData ? ' ('.\strlen($mData).')' : ''), $this->oLogger->Write($sCmd.' '.$sUrl.('PUT' === $sCmd && null !== $mData ? ' ('.\strlen($mData).')' : ''),
\MailSo\Log\Enumerations\Type::INFO, 'DAV'); \MailSo\Log\Enumerations\Type::INFO, 'DAV');
@ -183,7 +183,7 @@ class PdoAddressBook
{ {
$this->oLogger->WriteException($oException); $this->oLogger->WriteException($oException);
} }
return $oResponse; return $oResponse;
} }
@ -199,13 +199,13 @@ class PdoAddressBook
public function Sync($sEmail, $sUrl, $sUser, $sPassword, $sProxy = '') public function Sync($sEmail, $sUrl, $sUser, $sPassword, $sProxy = '')
{ {
$this->SyncDatabase(); $this->SyncDatabase();
$iUserID = $this->getUserId($sEmail); $iUserID = $this->getUserId($sEmail);
if (0 >= $iUserID) if (0 >= $iUserID)
{ {
return false; return false;
} }
$aUrl = \parse_url($sUrl); $aUrl = \parse_url($sUrl);
if (!\is_array($aUrl)) if (!\is_array($aUrl))
{ {
@ -233,6 +233,9 @@ class PdoAddressBook
$oClient = new \Sabre\DAV\Client($aSettings); $oClient = new \Sabre\DAV\Client($aSettings);
$oClient->setVerifyPeer(false); $oClient->setVerifyPeer(false);
$this->oLogger->AddSecret($sPassword);
$this->oLogger->Write('User: '.$aSettings['userName'].', Url: '.$sUrl, \MailSo\Log\Enumerations\Type::INFO, 'DAV');
$aRemoteSyncData = $this->prepearRemoteSyncData($oClient, $sPath); $aRemoteSyncData = $this->prepearRemoteSyncData($oClient, $sPath);
if (false === $aRemoteSyncData) if (false === $aRemoteSyncData)
{ {
@ -276,7 +279,7 @@ class PdoAddressBook
//+++new or newer (from db) //+++new or newer (from db)
foreach ($aDatabaseSyncData as $sKey => $aData) foreach ($aDatabaseSyncData as $sKey => $aData)
{ {
if (!$aData['deleted'] && if (!$aData['deleted'] &&
(empty($aData['etag']) && !isset($aRemoteSyncData[$sKey])) // new (empty($aData['etag']) && !isset($aRemoteSyncData[$sKey])) // new
|| ||
(!empty($aData['etag']) && isset($aRemoteSyncData[$sKey]) && // newer (!empty($aData['etag']) && isset($aRemoteSyncData[$sKey]) && // newer
@ -302,7 +305,7 @@ class PdoAddressBook
$oResponse = $this->davClientRequest($oClient, 'PUT', $oResponse = $this->davClientRequest($oClient, 'PUT',
$sPath.$oContact->CardDavNameUri(), $oContact->ToVCard($sExsistensBody)); $sPath.$oContact->CardDavNameUri(), $oContact->ToVCard($sExsistensBody));
if ($oResponse && isset($oResponse['headers'], $oResponse['headers']['etag'])) if ($oResponse && isset($oResponse['headers'], $oResponse['headers']['etag']))
{ {
$sEtag = \trim(\trim($oResponse['headers']['etag']), '"\''); $sEtag = \trim(\trim($oResponse['headers']['etag']), '"\'');
@ -314,7 +317,7 @@ class PdoAddressBook
} }
} }
} }
unset($oContact); unset($oContact);
} }
} }
@ -348,7 +351,7 @@ class PdoAddressBook
{ {
$oContact = new \RainLoop\Providers\AddressBook\Classes\Contact(); $oContact = new \RainLoop\Providers\AddressBook\Classes\Contact();
} }
$oContact->PopulateByVCard($sBody, $oContact->PopulateByVCard($sBody,
!empty($oResponse['headers']['etag']) ? \trim(\trim($oResponse['headers']['etag']), '"\'') : ''); !empty($oResponse['headers']['etag']) ? \trim(\trim($oResponse['headers']['etag']), '"\'') : '');
@ -421,16 +424,16 @@ class PdoAddressBook
{ {
$this->SyncDatabase(); $this->SyncDatabase();
} }
$iUserID = $this->getUserId($sEmail); $iUserID = $this->getUserId($sEmail);
$iIdContact = 0 < \strlen($oContact->IdContact) && \is_numeric($oContact->IdContact) ? (int) $oContact->IdContact : 0; $iIdContact = 0 < \strlen($oContact->IdContact) && \is_numeric($oContact->IdContact) ? (int) $oContact->IdContact : 0;
$bUpdate = 0 < $iIdContact; $bUpdate = 0 < $iIdContact;
$oContact->UpdateDependentValues(); $oContact->UpdateDependentValues();
$oContact->Changed = \time(); $oContact->Changed = \time();
try try
{ {
if ($this->isTransactionSupported()) if ($this->isTransactionSupported())
@ -465,6 +468,14 @@ class PdoAddressBook
':id_contact' => array($iIdContact, \PDO::PARAM_INT) ':id_contact' => array($iIdContact, \PDO::PARAM_INT)
) )
); );
// clear previos tags
$this->prepareAndExecute(
'DELETE FROM rainloop_ab_tags_contacts WHERE id_contact = :id_contact',
array(
':id_contact' => array($iIdContact, \PDO::PARAM_INT)
)
);
} }
else else
{ {
@ -517,6 +528,44 @@ class PdoAddressBook
'(:id_contact, :id_user, :prop_type, :prop_type_str, :prop_value, :prop_value_custom, :prop_frec)'; '(:id_contact, :id_user, :prop_type, :prop_type_str, :prop_value, :prop_value_custom, :prop_frec)';
$this->prepareAndExecute($sSql, $aParams, true); $this->prepareAndExecute($sSql, $aParams, true);
$aTags = array();
$aContactTags = $this->GetContactTags($sEmail);
$fFindFunc = function ($sName) use ($aContactTags) {
$iResult = 0;
foreach ($aContactTags as $oItem)
{
if ($oItem && $oItem->Name === $sName)
{
$iResult = (int) $oItem->IdContactTag;
break;
}
}
return $iResult;
};
foreach ($oContact->Tags as $sTagName)
{
$iTagID = $fFindFunc($sTagName);
if (0 >= $iTagID)
{
$iTagID = $this->CreateTag($sEmail, $sTagName, false);
}
if (\is_int($iTagID) && 0 < $iTagID)
{
$aTags[] = array(
':id_tag' => array($iTagID, \PDO::PARAM_INT),
':id_contact' => array($iIdContact, \PDO::PARAM_INT)
);
}
}
$sSql = 'INSERT INTO rainloop_ab_tags_contacts (id_tag, id_contact) VALUES (:id_tag, :id_contact)';
$this->prepareAndExecute($sSql, $aTags, true);
} }
} }
catch (\Exception $oException) catch (\Exception $oException)
@ -537,6 +586,64 @@ class PdoAddressBook
return 0 < $iIdContact; return 0 < $iIdContact;
} }
/**
* @param string $sEmail
* @param string $sName
* @param bool $bSyncDb = true
*
* @return bool|int
*/
public function CreateTag($sEmail, $sName, $bSyncDb = true)
{
if ($bSyncDb)
{
$this->SyncDatabase();
}
$iUserID = $this->getUserId($sEmail);
$mResult = false;
try
{
if ($this->isTransactionSupported())
{
$this->beginTransaction();
}
$sSql = 'INSERT INTO rainloop_ab_tags '.
'(id_user, tag_name) VALUES (:id_user, :tag_name)';
$this->prepareAndExecute($sSql,
array(
':id_user' => array($iUserID, \PDO::PARAM_INT),
':tag_name' => array($sName, \PDO::PARAM_STR)
)
);
$sLast = $this->lastInsertId('rainloop_ab_contacts', 'id_contact');
if (\is_numeric($sLast) && 0 < (int) $sLast)
{
$mResult = (int) $sLast;
}
}
catch (\Exception $oException)
{
if ($this->isTransactionSupported())
{
$this->rollBack();
}
throw $oException;
}
if ($this->isTransactionSupported())
{
$this->commit();
}
return $mResult;
}
/** /**
* @param string $sEmail * @param string $sEmail
* @param array $aContactIds * @param array $aContactIds
@ -615,7 +722,7 @@ class PdoAddressBook
* @param int $iLimit = 20 * @param int $iLimit = 20
* @param string $sSearch = '' * @param string $sSearch = ''
* @param int $iResultCount = 0 * @param int $iResultCount = 0
* *
* @return array * @return array
*/ */
public function GetContacts($sEmail, $iOffset = 0, $iLimit = 20, $sSearch = '', &$iResultCount = 0) public function GetContacts($sEmail, $iOffset = 0, $iLimit = 20, $sSearch = '', &$iResultCount = 0)
@ -631,7 +738,7 @@ class PdoAddressBook
$iCount = 0; $iCount = 0;
$aSearchIds = array(); $aSearchIds = array();
$aPropertyFromSearchIds = array(); $aPropertyFromSearchIds = array();
if (0 < \strlen($sSearch)) if (0 < \strlen($sSearch))
{ {
$sCustomSearch = $this->specialConvertSearchValueCustomPhone($sSearch); $sCustomSearch = $this->specialConvertSearchValueCustomPhone($sSearch);
@ -645,7 +752,7 @@ class PdoAddressBook
PropertyType::EMAIl, PropertyType::FIRST_NAME, PropertyType::LAST_NAME, PropertyType::NICK_NAME, PropertyType::EMAIl, PropertyType::FIRST_NAME, PropertyType::LAST_NAME, PropertyType::NICK_NAME,
PropertyType::PHONE, PropertyType::WEB_PAGE PropertyType::PHONE, PropertyType::WEB_PAGE
)); ));
$sSql = 'SELECT id_user, id_prop, id_contact FROM rainloop_ab_properties '. $sSql = 'SELECT id_user, id_prop, id_contact FROM rainloop_ab_properties '.
'WHERE (id_user = :id_user) AND prop_type IN ('.$sSearchTypes.') AND (prop_value LIKE :search ESCAPE \'=\''. 'WHERE (id_user = :id_user) AND prop_type IN ('.$sSearchTypes.') AND (prop_value LIKE :search ESCAPE \'=\''.
(0 < \strlen($sCustomSearch) ? ' OR (prop_type = '.PropertyType::PHONE.' AND prop_value_custom <> \'\' AND prop_value_custom LIKE :search_custom_phone)' : ''). (0 < \strlen($sCustomSearch) ? ' OR (prop_type = '.PropertyType::PHONE.' AND prop_value_custom <> \'\' AND prop_value_custom LIKE :search_custom_phone)' : '').
@ -686,7 +793,7 @@ class PdoAddressBook
{ {
$sSql = 'SELECT COUNT(DISTINCT id_contact) as contact_count FROM rainloop_ab_properties '. $sSql = 'SELECT COUNT(DISTINCT id_contact) as contact_count FROM rainloop_ab_properties '.
'WHERE id_user = :id_user'; 'WHERE id_user = :id_user';
$aParams = array( $aParams = array(
':id_user' => array($iUserID, \PDO::PARAM_INT) ':id_user' => array($iUserID, \PDO::PARAM_INT)
); );
@ -704,10 +811,11 @@ class PdoAddressBook
$iResultCount = $iCount; $iResultCount = $iCount;
$aResult = array();
if (0 < $iCount) if (0 < $iCount)
{ {
$sSql = 'SELECT * FROM rainloop_ab_contacts WHERE deleted = 0 AND id_user = :id_user'; $sSql = 'SELECT * FROM rainloop_ab_contacts WHERE deleted = 0 AND id_user = :id_user';
$aParams = array( $aParams = array(
':id_user' => array($iUserID, \PDO::PARAM_INT) ':id_user' => array($iUserID, \PDO::PARAM_INT)
); );
@ -794,13 +902,136 @@ class PdoAddressBook
$oItem->UpdateDependentValues(); $oItem->UpdateDependentValues();
} }
return \array_values($aContacts); $aResult = \array_values($aContacts);
} }
} }
} }
} }
return array(); if (\is_array($aResult) && 0 < \count($aResult))
{
$aIdContacts = array();
$aIdTagsContacts = array();
$aTags = $this->GetContactTags($sEmail);
if (\is_array($aTags) && 0 < \count($aTags))
{
foreach ($aResult as $oItem)
{
$aIdContacts[$oItem->IdContact] = true;
}
if (0 < \count($aIdContacts))
{
$sSql = 'SELECT id_tag, id_contact FROM rainloop_ab_tags_contacts WHERE id_contact IN ('.\implode(',', \array_keys($aIdContacts)).')';
$oStmt = $this->prepareAndExecute($sSql);
if ($oStmt)
{
$aFetch = $oStmt->fetchAll(\PDO::FETCH_ASSOC);
if (\is_array($aFetch) && 0 < \count($aFetch))
{
foreach ($aFetch as $aItem)
{
if ($aItem && isset($aItem['id_tag'], $aItem['id_contact']))
{
$sID = (string) $aItem['id_contact'];
if (!isset($aIdTagsContacts[$sID]))
{
$aIdTagsContacts[$sID] = array();
}
$aIdTagsContacts[$sID][] = (string) $aItem['id_tag'];
}
}
}
unset($aFetch);
}
if (0 < \count($aIdTagsContacts))
{
$fFindFunc = function ($sID) use ($aTags) {
foreach ($aTags as $oItem)
{
if ($oItem && (string) $oItem->IdContactTag === $sID)
{
return\trim($oItem->Name);
}
}
return '';
};
foreach ($aResult as &$oItem)
{
$sID = $oItem ? (string) $oItem->IdContact : '';
if (0 < \strlen($sID) && isset($aIdTagsContacts[$sID]) && \is_array($aIdTagsContacts[$sID]))
{
$aNames = array();
foreach ($aIdTagsContacts[$sID] as $sSubID)
{
$sName = $fFindFunc($sSubID);
if (0 < \strlen($sName))
{
$aNames[] = $sName;
}
}
$oItem->Tags = $aNames;
}
}
}
}
}
}
return $aResult;
}
/**
* @param string $sEmail
*
* @return array
*/
public function GetContactTags($sEmail)
{
$this->SyncDatabase();
$iUserID = $this->getUserId($sEmail);
$sSql = 'SELECT id_tag, id_user, tag_name FROM rainloop_ab_tags WHERE id_user = :id_user ORDER BY tag_name ASC';
$aParams = array(
':id_user' => array($iUserID, \PDO::PARAM_INT)
);
$aResult = array();
$oStmt = $this->prepareAndExecute($sSql, $aParams);
if ($oStmt)
{
$aFetch = $oStmt->fetchAll(\PDO::FETCH_ASSOC);
if (\is_array($aFetch) && 0 < \count($aFetch))
{
foreach ($aFetch as $aItem)
{
$iIdContactTag = $aItem && isset($aItem['id_tag']) ? (int) $aItem['id_tag'] : 0;
if (0 < $iIdContactTag)
{
$oContactTag = new \RainLoop\Providers\AddressBook\Classes\Tag();
$oContactTag->IdContactTag = (string) $iIdContactTag;
$oContactTag->Name = isset($aItem['tag_name']) ? (string) $aItem['tag_name'] : '';
$oContactTag->ReadOnly = $iUserID !== (isset($aItem['id_user']) ? (int) $aItem['id_user'] : 0);
$aResult[] = $oContactTag;
}
}
}
}
return $aResult;
} }
/** /**
@ -924,7 +1155,7 @@ class PdoAddressBook
} }
$this->SyncDatabase(); $this->SyncDatabase();
$iUserID = $this->getUserId($sEmail); $iUserID = $this->getUserId($sEmail);
$sTypes = implode(',', array( $sTypes = implode(',', array(
@ -933,7 +1164,7 @@ class PdoAddressBook
$sSql = 'SELECT id_contact, id_prop, prop_type, prop_value FROM rainloop_ab_properties '. $sSql = 'SELECT id_contact, id_prop, prop_type, prop_value FROM rainloop_ab_properties '.
'WHERE (id_user = :id_user) AND prop_type IN ('.$sTypes.') AND prop_value LIKE :search ESCAPE \'=\''; 'WHERE (id_user = :id_user) AND prop_type IN ('.$sTypes.') AND prop_value LIKE :search ESCAPE \'=\'';
$aParams = array( $aParams = array(
':id_user' => array($iUserID, \PDO::PARAM_INT), ':id_user' => array($iUserID, \PDO::PARAM_INT),
':limit' => array($iLimit, \PDO::PARAM_INT), ':limit' => array($iLimit, \PDO::PARAM_INT),
@ -944,7 +1175,7 @@ class PdoAddressBook
$sSql .= ' LIMIT :limit'; $sSql .= ' LIMIT :limit';
$aResult = array(); $aResult = array();
$oStmt = $this->prepareAndExecute($sSql, $aParams); $oStmt = $this->prepareAndExecute($sSql, $aParams);
if ($oStmt) if ($oStmt)
{ {
@ -960,7 +1191,7 @@ class PdoAddressBook
$iIdContact = $aItem && isset($aItem['id_contact']) ? (int) $aItem['id_contact'] : 0; $iIdContact = $aItem && isset($aItem['id_contact']) ? (int) $aItem['id_contact'] : 0;
$iIdProp = $aItem && isset($aItem['id_prop']) ? (int) $aItem['id_prop'] : 0; $iIdProp = $aItem && isset($aItem['id_prop']) ? (int) $aItem['id_prop'] : 0;
$iType = $aItem && isset($aItem['prop_type']) ? (int) $aItem['prop_type'] : 0; $iType = $aItem && isset($aItem['prop_type']) ? (int) $aItem['prop_type'] : 0;
if (0 < $iIdContact && 0 < $iIdProp) if (0 < $iIdContact && 0 < $iIdProp)
{ {
$aIdContacts[$iIdContact] = $iIdContact; $aIdContacts[$iIdContact] = $iIdContact;
@ -985,7 +1216,7 @@ class PdoAddressBook
if (0 < count($aIdContacts)) if (0 < count($aIdContacts))
{ {
$oStmt->closeCursor(); $oStmt->closeCursor();
$sTypes = \implode(',', array( $sTypes = \implode(',', array(
PropertyType::EMAIl, PropertyType::FIRST_NAME, PropertyType::LAST_NAME, PropertyType::NICK_NAME PropertyType::EMAIl, PropertyType::FIRST_NAME, PropertyType::LAST_NAME, PropertyType::NICK_NAME
)); ));
@ -1042,10 +1273,10 @@ class PdoAddressBook
{ {
$bName = \in_array(PropertyType::FIRST_NAME, $aContactAllAccess[$iId]) || \in_array(PropertyType::LAST_NAME, $aContactAllAccess[$iId]); $bName = \in_array(PropertyType::FIRST_NAME, $aContactAllAccess[$iId]) || \in_array(PropertyType::LAST_NAME, $aContactAllAccess[$iId]);
$bNick = \in_array(PropertyType::NICK_NAME, $aContactAllAccess[$iId]); $bNick = \in_array(PropertyType::NICK_NAME, $aContactAllAccess[$iId]);
$aNameItem = isset($aNames[$iId]) && \is_array($aNames[$iId]) ? $aNames[$iId] : array('', ''); $aNameItem = isset($aNames[$iId]) && \is_array($aNames[$iId]) ? $aNames[$iId] : array('', '');
$sNameItem = \trim($aNameItem[0].' '.$aNameItem[1]); $sNameItem = \trim($aNameItem[0].' '.$aNameItem[1]);
$sNickItem = isset($aNicks[$iId]) ? $aNicks[$iId] : ''; $sNickItem = isset($aNicks[$iId]) ? $aNicks[$iId] : '';
foreach ($aItems as $sEmail) foreach ($aItems as $sEmail)
@ -1054,7 +1285,7 @@ class PdoAddressBook
{ {
$aResult[] = array($sEmail, $sNameItem); $aResult[] = array($sEmail, $sNameItem);
} }
if ($bNick) if ($bNick)
{ {
$aResult[] = array($sEmail, $sNickItem); $aResult[] = array($sEmail, $sNickItem);
@ -1089,7 +1320,7 @@ class PdoAddressBook
{ {
$aResult = \array_slice($aResult, 0, $iLimit); $aResult = \array_slice($aResult, 0, $iLimit);
} }
return $aResult; return $aResult;
} }
} }
@ -1121,7 +1352,7 @@ class PdoAddressBook
$aEmailsObjects = \array_filter($aEmailsObjects, function ($oItem) { $aEmailsObjects = \array_filter($aEmailsObjects, function ($oItem) {
return !!$oItem; return !!$oItem;
}); });
if (0 === \count($aEmailsObjects)) if (0 === \count($aEmailsObjects))
{ {
throw new \InvalidArgumentException('Empty Emails argument'); throw new \InvalidArgumentException('Empty Emails argument');
@ -1156,7 +1387,7 @@ class PdoAddressBook
} }
} }
} }
$aEmailsToCreate = \array_filter($aEmailsObjects, function ($oItem) use ($aExists, &$aEmailsToUpdate) { $aEmailsToCreate = \array_filter($aEmailsObjects, function ($oItem) use ($aExists, &$aEmailsToUpdate) {
if ($oItem) if ($oItem)
{ {
@ -1185,7 +1416,7 @@ class PdoAddressBook
} }
} }
} }
unset($aEmails, $aEmailsObjects); unset($aEmails, $aEmailsObjects);
if (0 < \count($aEmailsToCreate)) if (0 < \count($aEmailsToCreate))
@ -1225,7 +1456,7 @@ class PdoAddressBook
$oContact->Properties[] = $oPropName; $oContact->Properties[] = $oPropName;
} }
if (0 < \strlen($sLast)) if (0 < \strlen($sLast))
{ {
$oPropName = new \RainLoop\Providers\AddressBook\Classes\Property(); $oPropName = new \RainLoop\Providers\AddressBook\Classes\Property();
@ -1240,17 +1471,17 @@ class PdoAddressBook
{ {
$this->ContactSave($sEmail, $oContact); $this->ContactSave($sEmail, $oContact);
} }
$oContact->Clear(); $oContact->Clear();
} }
} }
$sSql = 'UPDATE rainloop_ab_properties SET prop_frec = prop_frec + 1 WHERE id_user = :id_user AND prop_type = :prop_type'; $sSql = 'UPDATE rainloop_ab_properties SET prop_frec = prop_frec + 1 WHERE id_user = :id_user AND prop_type = :prop_type';
$aEmailsQuoted = \array_map(function ($mItem) use ($self) { $aEmailsQuoted = \array_map(function ($mItem) use ($self) {
return $self->quoteValue($mItem); return $self->quoteValue($mItem);
}, $aEmailsToUpdate); }, $aEmailsToUpdate);
if (1 === \count($aEmailsQuoted)) if (1 === \count($aEmailsQuoted))
{ {
$sSql .= ' AND prop_value = '.$aEmailsQuoted[0]; $sSql .= ' AND prop_value = '.$aEmailsQuoted[0];
@ -1259,7 +1490,7 @@ class PdoAddressBook
{ {
$sSql .= ' AND prop_value IN ('.\implode(',', $aEmailsQuoted).')'; $sSql .= ' AND prop_value IN ('.\implode(',', $aEmailsQuoted).')';
} }
return !!$this->prepareAndExecute($sSql, array( return !!$this->prepareAndExecute($sSql, array(
':id_user' => array($iUserID, \PDO::PARAM_INT), ':id_user' => array($iUserID, \PDO::PARAM_INT),
':prop_type' => array(PropertyType::EMAIl, \PDO::PARAM_INT) ':prop_type' => array(PropertyType::EMAIl, \PDO::PARAM_INT)
@ -1506,7 +1737,7 @@ SQLITEINITIAL;
break; break;
} }
return false; return $mCache;
} }
/** /**

View file

@ -315,7 +315,7 @@ class Client {
// Return headers as part of the response // Return headers as part of the response
CURLOPT_HEADER => true, CURLOPT_HEADER => true,
CURLOPT_POSTFIELDS => $body, CURLOPT_POSTFIELDS => $body,
CURLOPT_USERAGENT => 'RainLoop DAV Client', CURLOPT_USERAGENT => 'RainLoop DAV Client', // TODO rainloop
// Automatically follow redirects // Automatically follow redirects
CURLOPT_FOLLOWLOCATION => true, CURLOPT_FOLLOWLOCATION => true,
CURLOPT_MAXREDIRS => 5, CURLOPT_MAXREDIRS => 5,
@ -323,9 +323,13 @@ class Client {
if($this->verifyPeer !== null) { if($this->verifyPeer !== null) {
$curlSettings[CURLOPT_SSL_VERIFYPEER] = $this->verifyPeer; $curlSettings[CURLOPT_SSL_VERIFYPEER] = $this->verifyPeer;
// TODO rainloop
if (!$this->verifyPeer) {
$curlSettings[CURLOPT_SSL_VERIFYHOST] = 0;
} // ---
} }
if($this->trustedCertificates) { if($this->trustedCertificates) {
$curlSettings[CURLOPT_CAINFO] = $this->trustedCertificates; $curlSettings[CURLOPT_CAINFO] = $this->trustedCertificates;
} }
@ -459,6 +463,7 @@ class Client {
// @codeCoverageIgnoreStart // @codeCoverageIgnoreStart
protected function curlRequest($url, $settings) { protected function curlRequest($url, $settings) {
// TODO rainloop
$curl = curl_init($url); $curl = curl_init($url);
$sSafeMode = strtolower(trim(@ini_get('safe_mode'))); $sSafeMode = strtolower(trim(@ini_get('safe_mode')));
$bSafeMode = 'on' === $sSafeMode || '1' === $sSafeMode; $bSafeMode = 'on' === $sSafeMode || '1' === $sSafeMode;

View file

@ -1,11 +1,11 @@
<div class="popups"> <div class="popups">
<div class="modal hide b-contacts-content" data-bind="modal: modalVisibility"> <div class="modal hide b-contacts-content" data-bind="modal: modalVisibility">
<div class="modal-header b-header-toolbar g-ui-user-select-none"> <div class="modal-header b-header-toolbar g-ui-user-select-none">
<button type="button" class="close" data-bind="command: cancelCommand">&times;</button> <button type="button" class="close" data-bind="command: cancelCommand">&times;</button>
<div class="btn-toolbar"> <div class="btn-toolbar">
<div class="btn-group"> <div class="btn-group">
<a class="btn button-create-contact" data-bind="command: newCommand"> <a class="btn button-create-contact" data-bind="command: newCommand">
<i class="icon-plus"></i> <i class="icon-plus"></i>
@ -126,25 +126,41 @@
<ul class="dropdown-menu g-ui-menu" style="text-align: left" tabindex="-1" role="menu" aria-labelledby="button-add-prop-dropdown-id"> <ul class="dropdown-menu g-ui-menu" style="text-align: left" tabindex="-1" role="menu" aria-labelledby="button-add-prop-dropdown-id">
<li class="e-item" role="presentation"> <li class="e-item" role="presentation">
<a class="e-link menuitem" href="#" tabindex="-1" data-bind="click: addNewEmail"> <a class="e-link menuitem" href="#" tabindex="-1" data-bind="click: addNewEmail">
<i class="icon-none"></i>
&nbsp;&nbsp;
<span class="i18n" data-i18n-text="CONTACTS/ADD_MENU_EMAIL"></span> <span class="i18n" data-i18n-text="CONTACTS/ADD_MENU_EMAIL"></span>
</a> </a>
</li> </li>
<li class="e-item" role="presentation"> <li class="e-item" role="presentation">
<a class="e-link menuitem" href="#" tabindex="-1" data-bind="click: addNewPhone"> <a class="e-link menuitem" href="#" tabindex="-1" data-bind="click: addNewPhone">
<i class="icon-none"></i>
&nbsp;&nbsp;
<span class="i18n" data-i18n-text="CONTACTS/ADD_MENU_PHONE"></span> <span class="i18n" data-i18n-text="CONTACTS/ADD_MENU_PHONE"></span>
</a> </a>
</li> </li>
<li class="e-item" role="presentation"> <li class="e-item" role="presentation">
<a class="e-link menuitem" href="#" tabindex="-1" data-bind="click: addNewWeb"> <a class="e-link menuitem" href="#" tabindex="-1" data-bind="click: addNewWeb">
<i class="icon-none"></i>
&nbsp;&nbsp;
<span class="i18n" data-i18n-text="CONTACTS/ADD_MENU_URL"></span> <span class="i18n" data-i18n-text="CONTACTS/ADD_MENU_URL"></span>
</a> </a>
</li> </li>
<li class="divider" role="presentation"></li> <li class="divider" role="presentation"></li>
<li class="e-item" role="presentation"> <li class="e-item" role="presentation">
<a class="e-link menuitem" href="#" tabindex="-1" data-bind="click: addNewNickname"> <a class="e-link menuitem" href="#" tabindex="-1" data-bind="click: addNewNickname">
<i class="icon-none"></i>
&nbsp;&nbsp;
<span class="i18n" data-i18n-text="CONTACTS/ADD_MENU_NICKNAME"></span> <span class="i18n" data-i18n-text="CONTACTS/ADD_MENU_NICKNAME"></span>
</a> </a>
</li> </li>
<li class="divider" role="presentation"></li>
<li class="e-item" role="presentation">
<a class="e-link menuitem" href="#" tabindex="-1" data-bind="click: addNewTag">
<i class="icon-tags"></i>
&nbsp;&nbsp;
<span class="i18n" data-i18n-text="CONTACTS/ADD_MENU_TAGS"></span>
</a>
</li>
<!-- <li class="e-item" role="presentation"> <!-- <li class="e-item" role="presentation">
<a class="e-link menuitem" href="#" tabindex="-1" data-bind="click: addNewAddress"> <a class="e-link menuitem" href="#" tabindex="-1" data-bind="click: addNewAddress">
<span class="i18n" data-i18n-text="CONTACTS/ADD_MENU_ADDRESS"></span> <span class="i18n" data-i18n-text="CONTACTS/ADD_MENU_ADDRESS"></span>
@ -247,6 +263,18 @@
</div> </div>
</div> </div>
</div> </div>
<div class="control-group" data-bind="visible: !viewReadOnly() && viewTags.visibility()">
<label class="control-label remove-padding-top fix-width">
<i class="icon-tags iconsize24" data-tooltip-placement="left" data-bind="tooltip: 'CONTACTS/LABEL_TAGS'"></i>
</label>
<div class="controls fix-width">
<div class="property-line">
<div class="tags-property-container">
<input type="text" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" data-bind="contactTags: viewTags" />
</div>
</div>
</div>
</div>
<div class="control-group"> <div class="control-group">
<div class="controls fix-width"> <div class="controls fix-width">
<br /> <br />
@ -254,12 +282,12 @@
</div> </div>
</div> </div>
</div> </div>
<!-- <div class="e-read-only-sign"> <!-- <div class="e-read-only-sign">
<i class="icon-lock iconsize24" data-tooltip-placement="left" data-bind="tooltip: 'CONTACTS/LABEL_READ_ONLY'"></i> <i class="icon-lock iconsize24" data-tooltip-placement="left" data-bind="tooltip: 'CONTACTS/LABEL_READ_ONLY'"></i>
</div>--> </div>-->
</div> </div>
</div> </div>
</div> </div>

View file

@ -39,8 +39,8 @@
<br /> <br />
<select class="span2" data-bind="value: imapSecure"> <select class="span2" data-bind="value: imapSecure">
<option value="0">None</option> <option value="0">None</option>
<option value="1">SSL</option> <option value="1">SSL/TLS</option>
<option value="2">TLS</option> <option value="2">STARTTLS</option>
</select> </select>
<br /> <br />
<br /> <br />
@ -72,8 +72,8 @@
<br /> <br />
<select class="span2" data-bind="value: smtpSecure"> <select class="span2" data-bind="value: smtpSecure">
<option value="0">None</option> <option value="0">None</option>
<option value="1">SSL</option> <option value="1">SSL/TLS</option>
<option value="2">TLS</option> <option value="2">STARTTLS</option>
</select> </select>
<br /> <br />
<br /> <br />

View file

@ -167,6 +167,7 @@ LABEL_EMAIL = "Email"
LABEL_PHONE = "Phone" LABEL_PHONE = "Phone"
LABEL_WEB = "Web" LABEL_WEB = "Web"
LABEL_BIRTHDAY = "Birthday" LABEL_BIRTHDAY = "Birthday"
LABEL_TAGS = "Tags"
LINK_ADD_EMAIL = "Add an email address" LINK_ADD_EMAIL = "Add an email address"
LINK_ADD_PHONE = "Add a phone" LINK_ADD_PHONE = "Add a phone"
LINK_BIRTHDAY = "Birthday" LINK_BIRTHDAY = "Birthday"
@ -184,6 +185,7 @@ ADD_MENU_PHONE = "Phone"
ADD_MENU_URL = "URL" ADD_MENU_URL = "URL"
ADD_MENU_ADDRESS = "Address" ADD_MENU_ADDRESS = "Address"
ADD_MENU_BIRTHDAY = "Birthday" ADD_MENU_BIRTHDAY = "Birthday"
ADD_MENU_TAGS = "Tags"
BUTTON_SHARE_NONE = "None" BUTTON_SHARE_NONE = "None"
BUTTON_SHARE_ALL = "Everyone" BUTTON_SHARE_ALL = "Everyone"
BUTTON_SYNC = "Synchronization (CardDAV)" BUTTON_SYNC = "Synchronization (CardDAV)"

View file

@ -637,7 +637,7 @@
border-radius: 8px; border-radius: 8px;
} }
/*! normalize.css 2012-03-11T12:53 UTC - http://github.com/necolas/normalize.css */ /*! normalize.css 2012-03-11T12:53 UTC - http://github.com/necolas/normalize.css */
/* ============================================================================= /* =============================================================================
@ -1142,7 +1142,7 @@ table {
border-collapse: collapse; border-collapse: collapse;
border-spacing: 0; border-spacing: 0;
} }
@charset "UTF-8"; @charset "UTF-8";
@font-face { @font-face {
@ -1510,7 +1510,7 @@ table {
.icon-help:before { .icon-help:before {
content: "\e06c"; content: "\e06c";
} }
/** initial setup **/ /** initial setup **/
.nano { .nano {
/* /*
@ -1627,7 +1627,7 @@ table {
.nano > .pane2:hover > .slider2, .nano > .pane2.active > .slider2 { .nano > .pane2:hover > .slider2, .nano > .pane2.active > .slider2 {
background-color: rgba(0, 0, 0, 0.4); background-color: rgba(0, 0, 0, 0.4);
} }
/* Magnific Popup CSS */ /* Magnific Popup CSS */
.mfp-bg { .mfp-bg {
top: 0; top: 0;
@ -1992,7 +1992,7 @@ img.mfp-img {
right: 0; right: 0;
padding-top: 0; } padding-top: 0; }
/* overlay at start */ /* overlay at start */
.mfp-fade.mfp-bg { .mfp-fade.mfp-bg {
@ -2038,7 +2038,7 @@ img.mfp-img {
-moz-transform: translateX(50px); -moz-transform: translateX(50px);
transform: translateX(50px); transform: translateX(50px);
} }
.simple-pace { .simple-pace {
-webkit-pointer-events: none; -webkit-pointer-events: none;
pointer-events: none; pointer-events: none;
@ -2109,7 +2109,7 @@ img.mfp-img {
@keyframes simple-pace-stripe-animation { @keyframes simple-pace-stripe-animation {
0% { transform: none; transform: none; } 0% { transform: none; transform: none; }
100% { transform: translate(-32px, 0); transform: translate(-32px, 0); } 100% { transform: translate(-32px, 0); transform: translate(-32px, 0); }
} }
.inputosaurus-container { .inputosaurus-container {
background-color:#fff; background-color:#fff;
border:1px solid #bcbec0; border:1px solid #bcbec0;
@ -2177,7 +2177,7 @@ img.mfp-img {
box-shadow:none; box-shadow:none;
} }
.inputosaurus-input-hidden { display:none; } .inputosaurus-input-hidden { display:none; }
.flag-wrapper { .flag-wrapper {
width: 24px; width: 24px;
height: 16px; height: 16px;
@ -2221,7 +2221,7 @@ img.mfp-img {
.flag.flag-pt-br {background-position: -192px -11px} .flag.flag-pt-br {background-position: -192px -11px}
.flag.flag-cn, .flag.flag-zh-tw, .flag.flag-zh-cn, .flag.flag-zh-hk {background-position: -208px -22px} .flag.flag-cn, .flag.flag-zh-tw, .flag.flag-zh-cn, .flag.flag-zh-hk {background-position: -208px -22px}
/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ /* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */
.clearfix { .clearfix {
*zoom: 1; *zoom: 1;
@ -6522,6 +6522,13 @@ html.no-rgba .modal {
-o-transition: border linear .2s, box-shadow linear .2s; -o-transition: border linear .2s, box-shadow linear .2s;
transition: border linear .2s, box-shadow linear .2s; transition: border linear .2s, box-shadow linear .2s;
} }
.inputosaurus-container.inputosaurus-focused {
background-color: #fff;
border: 1px solid #999999;
-webkit-box-shadow: none;
-moz-box-shadow: none;
box-shadow: none;
}
.inputosaurus-container li { .inputosaurus-container li {
max-width: 500px; max-width: 500px;
background-color: #eee; background-color: #eee;
@ -7101,7 +7108,7 @@ html.ssm-state-tablet .b-contacts-content.modal .contactValueInput {
display: none; display: none;
} }
html.rl-left-panel-disabled #rl-left { html.rl-left-panel-disabled #rl-left {
width: 65px !important; width: 60px !important;
} }
html.rl-left-panel-disabled #rl-left .show-on-panel-disabled { html.rl-left-panel-disabled #rl-left .show-on-panel-disabled {
display: block; display: block;
@ -7121,7 +7128,7 @@ html.rl-left-panel-disabled #rl-left.ui-state-disabled {
filter: alpha(opacity=100); filter: alpha(opacity=100);
} }
html.rl-left-panel-disabled #rl-right { html.rl-left-panel-disabled #rl-right {
left: 65px !important; left: 60px !important;
} }
.ui-resizable-helper { .ui-resizable-helper {
border-right: 5px solid #777; border-right: 5px solid #777;
@ -8637,6 +8644,29 @@ html.rl-message-fullscreen .messageView .b-content .buttonFull {
.b-contacts-content.modal .b-view-content .content { .b-contacts-content.modal .b-view-content .content {
-webkit-overflow-scrolling: touch; -webkit-overflow-scrolling: touch;
} }
.b-contacts-content.modal .b-view-content .tags-property-container {
font-size: 18px;
width: 400px;
}
.b-contacts-content.modal .b-view-content .tags-property-container .inputosaurus-container {
border-width: 1px;
border-color: transparent;
-webkit-box-shadow: none;
-moz-box-shadow: none;
box-shadow: none;
}
.b-contacts-content.modal .b-view-content .tags-property-container .inputosaurus-container:hover {
-webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
-moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
border-color: #ccc;
}
.b-contacts-content.modal .b-view-content .tags-property-container .inputosaurus-container.inputosaurus-focused {
-webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
-moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
border-color: #999;
}
.b-contacts-content.modal .b-view-content .contactValueStatic, .b-contacts-content.modal .b-view-content .contactValueStatic,
.b-contacts-content.modal .b-view-content .contactValueLargeStatic, .b-contacts-content.modal .b-view-content .contactValueLargeStatic,
.b-contacts-content.modal .b-view-content .contactValueTextAreaStatic { .b-contacts-content.modal .b-view-content .contactValueTextAreaStatic {

File diff suppressed because one or more lines are too long

View file

@ -1,5 +1,5 @@
/*! RainLoop Webmail Admin Module (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ /*! RainLoop Webmail Admin Module (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */
(function (window, $, ko, crossroads, hasher, _) { (function (window, $, ko, crossroads, hasher, _) {
'use strict'; 'use strict';
@ -77,14 +77,14 @@ var
$document = $(window.document), $document = $(window.document),
NotificationClass = window.Notification && window.Notification.requestPermission ? window.Notification : null NotificationClass = window.Notification && window.Notification.requestPermission ? window.Notification : null
; ;
/*jshint onevar: false*/ /*jshint onevar: false*/
/** /**
* @type {?AdminApp} * @type {?AdminApp}
*/ */
var RL = null; var RL = null;
/*jshint onevar: true*/ /*jshint onevar: true*/
/** /**
* @type {?} * @type {?}
*/ */
@ -233,7 +233,7 @@ if (Globals.bAllowPdfPreview && navigator && navigator.mimeTypes)
return oType && 'application/pdf' === oType.type; return oType && 'application/pdf' === oType.type;
}); });
} }
Consts.Defaults = {}; Consts.Defaults = {};
Consts.Values = {}; Consts.Values = {};
Consts.DataImages = {}; Consts.DataImages = {};
@ -351,7 +351,7 @@ Consts.DataImages.UserDotPic = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA
* @type {string} * @type {string}
*/ */
Consts.DataImages.TranspPic = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAC0lEQVQIW2NkAAIAAAoAAggA9GkAAAAASUVORK5CYII='; Consts.DataImages.TranspPic = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAC0lEQVQIW2NkAAIAAAoAAggA9GkAAAAASUVORK5CYII=';
/** /**
* @enum {string} * @enum {string}
*/ */
@ -726,7 +726,7 @@ Enums.Notification = {
'UnknownNotification': 999, 'UnknownNotification': 999,
'UnknownError': 999 'UnknownError': 999
}; };
Utils.trim = $.trim; Utils.trim = $.trim;
Utils.inArray = $.inArray; Utils.inArray = $.inArray;
Utils.isArray = _.isArray; Utils.isArray = _.isArray;
@ -1052,13 +1052,13 @@ Utils.i18nToNode = function (oElement)
{ {
jqThis.html(Utils.i18n(sKey)); jqThis.html(Utils.i18n(sKey));
} }
sKey = jqThis.data('i18n-placeholder'); sKey = jqThis.data('i18n-placeholder');
if (sKey) if (sKey)
{ {
jqThis.attr('placeholder', Utils.i18n(sKey)); jqThis.attr('placeholder', Utils.i18n(sKey));
} }
sKey = jqThis.data('i18n-title'); sKey = jqThis.data('i18n-title');
if (sKey) if (sKey)
{ {
@ -1196,7 +1196,7 @@ Utils.fixLongSubject = function (sSubject)
; ;
sSubject = Utils.trim(sSubject.replace(/[\s]+/, ' ')); sSubject = Utils.trim(sSubject.replace(/[\s]+/, ' '));
do do
{ {
oMatch = /^Re(\[([\d]+)\]|):[\s]{0,3}Re(\[([\d]+)\]|):/ig.exec(sSubject); oMatch = /^Re(\[([\d]+)\]|):[\s]{0,3}Re(\[([\d]+)\]|):/ig.exec(sSubject);
@ -1325,9 +1325,9 @@ Utils.initNotificationLanguage = function ()
NotificationI18N[Enums.Notification.CantSaveSettings] = Utils.i18n('NOTIFICATIONS/CANT_SAVE_SETTINGS'); NotificationI18N[Enums.Notification.CantSaveSettings] = Utils.i18n('NOTIFICATIONS/CANT_SAVE_SETTINGS');
NotificationI18N[Enums.Notification.CantSavePluginSettings] = Utils.i18n('NOTIFICATIONS/CANT_SAVE_PLUGIN_SETTINGS'); NotificationI18N[Enums.Notification.CantSavePluginSettings] = Utils.i18n('NOTIFICATIONS/CANT_SAVE_PLUGIN_SETTINGS');
NotificationI18N[Enums.Notification.DomainAlreadyExists] = Utils.i18n('NOTIFICATIONS/DOMAIN_ALREADY_EXISTS'); NotificationI18N[Enums.Notification.DomainAlreadyExists] = Utils.i18n('NOTIFICATIONS/DOMAIN_ALREADY_EXISTS');
NotificationI18N[Enums.Notification.CantInstallPackage] = Utils.i18n('NOTIFICATIONS/CANT_INSTALL_PACKAGE'); NotificationI18N[Enums.Notification.CantInstallPackage] = Utils.i18n('NOTIFICATIONS/CANT_INSTALL_PACKAGE');
NotificationI18N[Enums.Notification.CantDeletePackage] = Utils.i18n('NOTIFICATIONS/CANT_DELETE_PACKAGE'); NotificationI18N[Enums.Notification.CantDeletePackage] = Utils.i18n('NOTIFICATIONS/CANT_DELETE_PACKAGE');
NotificationI18N[Enums.Notification.InvalidPluginPackage] = Utils.i18n('NOTIFICATIONS/INVALID_PLUGIN_PACKAGE'); NotificationI18N[Enums.Notification.InvalidPluginPackage] = Utils.i18n('NOTIFICATIONS/INVALID_PLUGIN_PACKAGE');
@ -1340,7 +1340,7 @@ Utils.initNotificationLanguage = function ()
NotificationI18N[Enums.Notification.DemoSendMessageError] = Utils.i18n('NOTIFICATIONS/DEMO_SEND_MESSAGE_ERROR'); NotificationI18N[Enums.Notification.DemoSendMessageError] = Utils.i18n('NOTIFICATIONS/DEMO_SEND_MESSAGE_ERROR');
NotificationI18N[Enums.Notification.AccountAlreadyExists] = Utils.i18n('NOTIFICATIONS/ACCOUNT_ALREADY_EXISTS'); NotificationI18N[Enums.Notification.AccountAlreadyExists] = Utils.i18n('NOTIFICATIONS/ACCOUNT_ALREADY_EXISTS');
NotificationI18N[Enums.Notification.MailServerError] = Utils.i18n('NOTIFICATIONS/MAIL_SERVER_ERROR'); NotificationI18N[Enums.Notification.MailServerError] = Utils.i18n('NOTIFICATIONS/MAIL_SERVER_ERROR');
NotificationI18N[Enums.Notification.UnknownNotification] = Utils.i18n('NOTIFICATIONS/UNKNOWN_ERROR'); NotificationI18N[Enums.Notification.UnknownNotification] = Utils.i18n('NOTIFICATIONS/UNKNOWN_ERROR');
NotificationI18N[Enums.Notification.UnknownError] = Utils.i18n('NOTIFICATIONS/UNKNOWN_ERROR'); NotificationI18N[Enums.Notification.UnknownError] = Utils.i18n('NOTIFICATIONS/UNKNOWN_ERROR');
@ -1492,7 +1492,7 @@ Utils.initDataConstructorBySettings = function (oData)
oData.contactsAutosave = ko.observable(false); oData.contactsAutosave = ko.observable(false);
Globals.sAnimationType = Enums.InterfaceAnimation.Full; Globals.sAnimationType = Enums.InterfaceAnimation.Full;
oData.allowThemes = ko.observable(true); oData.allowThemes = ko.observable(true);
oData.allowCustomLogin = ko.observable(false); oData.allowCustomLogin = ko.observable(false);
oData.allowLanguagesOnSettings = ko.observable(true); oData.allowLanguagesOnSettings = ko.observable(true);
@ -1502,7 +1502,7 @@ Utils.initDataConstructorBySettings = function (oData)
oData.useThreads = ko.observable(true); oData.useThreads = ko.observable(true);
oData.replySameFolder = ko.observable(true); oData.replySameFolder = ko.observable(true);
oData.useCheckboxesInList = ko.observable(true); oData.useCheckboxesInList = ko.observable(true);
oData.layout = ko.observable(Enums.Layout.SidePreview); oData.layout = ko.observable(Enums.Layout.SidePreview);
oData.usePreviewPane = ko.computed(function () { oData.usePreviewPane = ko.computed(function () {
return Enums.Layout.NoPreview !== oData.layout(); return Enums.Layout.NoPreview !== oData.layout();
@ -1785,7 +1785,7 @@ Utils.setExpandedFolder = function (sFullNameHash, bExpanded)
{ {
aExpandedList = []; aExpandedList = [];
} }
if (bExpanded) if (bExpanded)
{ {
aExpandedList.push(sFullNameHash); aExpandedList.push(sFullNameHash);
@ -1802,7 +1802,7 @@ Utils.setExpandedFolder = function (sFullNameHash, bExpanded)
Utils.initLayoutResizer = function (sLeft, sRight, sClientSideKeyName) Utils.initLayoutResizer = function (sLeft, sRight, sClientSideKeyName)
{ {
var var
iDisabledWidth = 65, iDisabledWidth = 60,
iMinWidth = 155, iMinWidth = 155,
oLeft = $(sLeft), oLeft = $(sLeft),
oRight = $(sRight), oRight = $(sRight),
@ -1880,7 +1880,7 @@ Utils.initBlockquoteSwitcher = function (oMessageTextBody)
var $oList = $('blockquote:not(.rl-bq-switcher)', oMessageTextBody).filter(function () { var $oList = $('blockquote:not(.rl-bq-switcher)', oMessageTextBody).filter(function () {
return 0 === $(this).parent().closest('blockquote', oMessageTextBody).length; return 0 === $(this).parent().closest('blockquote', oMessageTextBody).length;
}); });
if ($oList && 0 < $oList.length) if ($oList && 0 < $oList.length)
{ {
$oList.each(function () { $oList.each(function () {
@ -2290,7 +2290,7 @@ Utils.resizeAndCrop = function (sUrl, iValue, fCallback)
oCtx.fillStyle = '#fff'; oCtx.fillStyle = '#fff';
oCtx.fillRect(0, 0, iValue, iValue); oCtx.fillRect(0, 0, iValue, iValue);
oCtx.drawImage(this, aDiff[0] / 2, aDiff[1] / 2, this.width - aDiff[0], this.height - aDiff[1], 0, 0, iValue, iValue); oCtx.drawImage(this, aDiff[0] / 2, aDiff[1] / 2, this.width - aDiff[0], this.height - aDiff[1], 0, 0, iValue, iValue);
fCallback(oCanvas.toDataURL('image/jpeg')); fCallback(oCanvas.toDataURL('image/jpeg'));
}; };
@ -2469,7 +2469,7 @@ Utils.detectDropdownVisibility = _.debounce(function () {
Globals.dropdownVisibility(!!_.find(BootstrapDropdowns, function (oItem) { Globals.dropdownVisibility(!!_.find(BootstrapDropdowns, function (oItem) {
return oItem.hasClass('open'); return oItem.hasClass('open');
})); }));
}, 50); }, 50);
// Base64 encode / decode // Base64 encode / decode
// http://www.webtoolkit.info/ // http://www.webtoolkit.info/
@ -2632,7 +2632,7 @@ Base64 = {
} }
}; };
/*jslint bitwise: false*/ /*jslint bitwise: false*/
ko.bindingHandlers.tooltip = { ko.bindingHandlers.tooltip = {
'init': function (oElement, fValueAccessor) { 'init': function (oElement, fValueAccessor) {
if (!Globals.bMobileDevice) if (!Globals.bMobileDevice)
@ -2707,7 +2707,7 @@ ko.bindingHandlers.tooltip3 = {
'init': function (oElement) { 'init': function (oElement) {
var $oEl = $(oElement); var $oEl = $(oElement);
$oEl.tooltip({ $oEl.tooltip({
'container': 'body', 'container': 'body',
'trigger': 'hover manual', 'trigger': 'hover manual',
@ -2726,7 +2726,7 @@ ko.bindingHandlers.tooltip3 = {
$document.click(function () { $document.click(function () {
$oEl.tooltip('hide'); $oEl.tooltip('hide');
}); });
}, },
'update': function (oElement, fValueAccessor) { 'update': function (oElement, fValueAccessor) {
var sValue = ko.utils.unwrapObservable(fValueAccessor()); var sValue = ko.utils.unwrapObservable(fValueAccessor());
@ -2757,7 +2757,7 @@ ko.bindingHandlers.openDropdownTrigger = {
$el.find('.dropdown-toggle').dropdown('toggle'); $el.find('.dropdown-toggle').dropdown('toggle');
Utils.detectDropdownVisibility(); Utils.detectDropdownVisibility();
} }
fValueAccessor()(false); fValueAccessor()(false);
} }
} }
@ -2854,7 +2854,7 @@ ko.bindingHandlers.clickOnTrue = {
ko.bindingHandlers.modal = { ko.bindingHandlers.modal = {
'init': function (oElement, fValueAccessor) { 'init': function (oElement, fValueAccessor) {
$(oElement).toggleClass('fade', !Globals.bMobileDevice).modal({ $(oElement).toggleClass('fade', !Globals.bMobileDevice).modal({
'keyboard': false, 'keyboard': false,
'show': ko.utils.unwrapObservable(fValueAccessor()) 'show': ko.utils.unwrapObservable(fValueAccessor())
@ -3169,11 +3169,19 @@ ko.bindingHandlers.emailsTags = {
'init': function(oElement, fValueAccessor) { 'init': function(oElement, fValueAccessor) {
var var
$oEl = $(oElement), $oEl = $(oElement),
fValue = fValueAccessor() fValue = fValueAccessor(),
fFocusCallback = function (bValue) {
if (fValue && fValue.focusTrigger)
{
fValue.focusTrigger(bValue);
}
}
; ;
$oEl.inputosaurus({ $oEl.inputosaurus({
'parseOnBlur': true, 'parseOnBlur': true,
'allowDragAndDrop': true,
'focusCallback': fFocusCallback,
'inputDelimiters': [',', ';'], 'inputDelimiters': [',', ';'],
'autoCompleteSource': function (oData, fResponse) { 'autoCompleteSource': function (oData, fResponse) {
RL.getAutocomplete(oData.term, function (aData) { RL.getAutocomplete(oData.term, function (aData) {
@ -3184,12 +3192,12 @@ ko.bindingHandlers.emailsTags = {
}, },
'parseHook': function (aInput) { 'parseHook': function (aInput) {
return _.map(aInput, function (sInputValue) { return _.map(aInput, function (sInputValue) {
var var
sValue = Utils.trim(sInputValue), sValue = Utils.trim(sInputValue),
oEmail = null oEmail = null
; ;
if ('' !== sValue) if ('' !== sValue)
{ {
oEmail = new EmailModel(); oEmail = new EmailModel();
@ -3219,8 +3227,83 @@ ko.bindingHandlers.emailsTags = {
if (fValue.focusTrigger) if (fValue.focusTrigger)
{ {
fValue.focusTrigger.subscribe(function () { fValue.focusTrigger.subscribe(function (bValue) {
$oEl.inputosaurus('focus'); if (bValue)
{
$oEl.inputosaurus('focus');
}
});
}
}
};
ko.bindingHandlers.contactTags = {
'init': function(oElement, fValueAccessor) {
var
$oEl = $(oElement),
fValue = fValueAccessor(),
fFocusCallback = function (bValue) {
if (fValue && fValue.focusTrigger)
{
fValue.focusTrigger(bValue);
}
}
;
$oEl.inputosaurus({
'parseOnBlur': true,
'allowDragAndDrop': false,
'focusCallback': fFocusCallback,
'inputDelimiters': [';'],
'outputDelimiter': ';',
'autoCompleteSource': function (oData, fResponse) {
RL.getContactsTagsAutocomplete(oData.term, function (aData) {
fResponse(_.map(aData, function (oTagItem) {
return oTagItem.toLine(false);
}));
});
},
'parseHook': function (aInput) {
return _.map(aInput, function (sInputValue) {
var
sValue = Utils.trim(sInputValue),
oTag = null
;
if ('' !== sValue)
{
oTag = new ContactTagModel();
oTag.name(sValue);
return [oTag.toLine(false), oTag];
}
return [sValue, null];
});
},
'change': _.bind(function (oEvent) {
$oEl.data('ContactsTagsValue', oEvent.target.value);
fValue(oEvent.target.value);
}, this)
});
fValue.subscribe(function (sValue) {
if ($oEl.data('ContactsTagsValue') !== sValue)
{
$oEl.val(sValue);
$oEl.data('ContactsTagsValue', sValue);
$oEl.inputosaurus('refresh');
}
});
if (fValue.focusTrigger)
{
fValue.focusTrigger.subscribe(function (bValue) {
if (bValue)
{
$oEl.inputosaurus('focus');
}
}); });
} }
} }
@ -3370,14 +3453,14 @@ ko.observable.fn.validateFunc = function (fFunc)
this.subscribe(function (sValue) { this.subscribe(function (sValue) {
this.hasFuncError(!fFunc(sValue)); this.hasFuncError(!fFunc(sValue));
}, this); }, this);
this.valueHasMutated(); this.valueHasMutated();
} }
return this; return this;
}; };
/** /**
* @constructor * @constructor
*/ */
@ -3689,7 +3772,7 @@ LinkBuilder.prototype.socialFacebook = function ()
{ {
return this.sServer + 'SocialFacebook' + ('' !== this.sSpecSuffix ? '/' + this.sSpecSuffix + '/' : ''); return this.sServer + 'SocialFacebook' + ('' !== this.sSpecSuffix ? '/' + this.sSpecSuffix + '/' : '');
}; };
/** /**
* @type {Object} * @type {Object}
*/ */
@ -3783,7 +3866,7 @@ Plugins.settingsGet = function (sPluginSection, sName)
}; };
/** /**
* @constructor * @constructor
*/ */
@ -3857,7 +3940,7 @@ CookieDriver.prototype.get = function (sKey)
return mResult; return mResult;
}; };
/** /**
* @constructor * @constructor
*/ */
@ -3928,7 +4011,7 @@ LocalStorageDriver.prototype.get = function (sKey)
return mResult; return mResult;
}; };
/** /**
* @constructor * @constructor
*/ */
@ -3971,7 +4054,7 @@ LocalStorage.prototype.get = function (iKey)
{ {
return this.oDriver ? this.oDriver.get('p' + iKey) : null; return this.oDriver ? this.oDriver.get('p' + iKey) : null;
}; };
/** /**
* @constructor * @constructor
*/ */
@ -3984,7 +4067,7 @@ KnoinAbstractBoot.prototype.bootstart = function ()
{ {
}; };
/** /**
* @param {string=} sPosition = '' * @param {string=} sPosition = ''
* @param {string=} sTemplate = '' * @param {string=} sTemplate = ''
@ -4002,7 +4085,7 @@ function KnoinAbstractViewModel(sPosition, sTemplate)
this.viewModelName = ''; this.viewModelName = '';
this.viewModelVisibility = ko.observable(false); this.viewModelVisibility = ko.observable(false);
this.modalVisibility = ko.observable(false).extend({'rateLimit': 0}); this.modalVisibility = ko.observable(false).extend({'rateLimit': 0});
this.viewModelDom = null; this.viewModelDom = null;
} }
@ -4057,20 +4140,27 @@ KnoinAbstractViewModel.prototype.restoreKeyScope = function ()
RL.data().keyScope(this.sCurrentKeyScope); RL.data().keyScope(this.sCurrentKeyScope);
}; };
KnoinAbstractViewModel.prototype.registerPopupEscapeKey = function () KnoinAbstractViewModel.prototype.registerPopupKeyDown = function ()
{ {
var self = this; var self = this;
$window.on('keydown', function (oEvent) { $window.on('keydown', function (oEvent) {
if (oEvent && Enums.EventKeyCode.Esc === oEvent.keyCode && self.modalVisibility && self.modalVisibility()) if (oEvent && self.modalVisibility && self.modalVisibility())
{ {
Utils.delegateRun(self, 'cancelCommand'); if (!this.bDisabeCloseOnEsc && Enums.EventKeyCode.Esc === oEvent.keyCode)
return false; {
Utils.delegateRun(self, 'cancelCommand');
return false;
}
else if (Enums.EventKeyCode.Backspace === oEvent.keyCode && !Utils.inFocus())
{
return false;
}
} }
return true; return true;
}); });
}; };
/** /**
* @param {string} sScreenName * @param {string} sScreenName
* @param {?=} aViewModels = [] * @param {?=} aViewModels = []
@ -4146,7 +4236,7 @@ KnoinAbstractScreen.prototype.__start = function ()
this.oCross = oRoute; this.oCross = oRoute;
} }
}; };
/** /**
* @constructor * @constructor
*/ */
@ -4230,7 +4320,7 @@ Knoin.prototype.buildViewModel = function (ViewModelClass, oScreen)
ViewModelClass.__builded = true; ViewModelClass.__builded = true;
ViewModelClass.__vm = oViewModel; ViewModelClass.__vm = oViewModel;
oViewModel.data = RL.data(); oViewModel.data = RL.data();
oViewModel.viewModelName = ViewModelClass.__name; oViewModel.viewModelName = ViewModelClass.__name;
if (oViewModelPlace && 1 === oViewModelPlace.length) if (oViewModelPlace && 1 === oViewModelPlace.length)
@ -4273,19 +4363,19 @@ Knoin.prototype.buildViewModel = function (ViewModelClass, oScreen)
self.viewModelDom.hide(); self.viewModelDom.hide();
}, 300); }, 300);
} }
}, oViewModel); }, oViewModel);
} }
Plugins.runHook('view-model-pre-build', [ViewModelClass.__name, oViewModel, oViewModelDom]); Plugins.runHook('view-model-pre-build', [ViewModelClass.__name, oViewModel, oViewModelDom]);
ko.applyBindings(oViewModel, oViewModelDom[0]); ko.applyBindings(oViewModel, oViewModelDom[0]);
Utils.delegateRun(oViewModel, 'onBuild', [oViewModelDom]); Utils.delegateRun(oViewModel, 'onBuild', [oViewModelDom]);
if (oViewModel && 'Popups' === sPosition && !oViewModel.bDisabeCloseOnEsc) if (oViewModel && 'Popups' === sPosition)
{ {
oViewModel.registerPopupEscapeKey(); oViewModel.registerPopupKeyDown();
} }
Plugins.runHook('view-model-post-build', [ViewModelClass.__name, oViewModel, oViewModelDom]); Plugins.runHook('view-model-post-build', [ViewModelClass.__name, oViewModel, oViewModelDom]);
} }
else else
@ -4387,7 +4477,7 @@ Knoin.prototype.screenOnRoute = function (sScreenName, sSubPart)
} }
_.defer(function () { _.defer(function () {
// hide screen // hide screen
if (self.oCurrentScreen) if (self.oCurrentScreen)
{ {
@ -4483,7 +4573,7 @@ Knoin.prototype.startScreens = function (aScreensClasses)
{ {
oScreen.__started = true; oScreen.__started = true;
oScreen.__start(); oScreen.__start();
Plugins.runHook('screen-pre-start', [oScreen.screenName(), oScreen]); Plugins.runHook('screen-pre-start', [oScreen.screenName(), oScreen]);
Utils.delegateRun(oScreen, 'onStart'); Utils.delegateRun(oScreen, 'onStart');
Plugins.runHook('screen-post-start', [oScreen.screenName(), oScreen]); Plugins.runHook('screen-post-start', [oScreen.screenName(), oScreen]);
@ -4546,7 +4636,7 @@ Knoin.prototype.bootstart = function ()
}; };
kn = new Knoin(); kn = new Knoin();
/** /**
* @param {string=} sEmail * @param {string=} sEmail
* @param {string=} sName * @param {string=} sName
@ -4910,7 +5000,51 @@ EmailModel.prototype.inputoTagLine = function ()
{ {
return 0 < this.name.length ? this.name + ' (' + this.email + ')' : this.email; return 0 < this.name.length ? this.name + ' (' + this.email + ')' : this.email;
}; };
/**
* @constructor
*/
function ContactTagModel()
{
this.idContactTag = 0;
this.name = ko.observable('');
this.readOnly = false;
}
ContactTagModel.prototype.parse = function (oItem)
{
var bResult = false;
if (oItem && 'Object/Tag' === oItem['@Object'])
{
this.idContact = Utils.pInt(oItem['IdContactTag']);
this.name(Utils.pString(oItem['Name']));
this.readOnly = !!oItem['ReadOnly'];
bResult = true;
}
return bResult;
};
/**
* @param {string} sSearch
* @return {boolean}
*/
ContactTagModel.prototype.filterHelper = function (sSearch)
{
return this.name().toLowerCase().indexOf(sSearch.toLowerCase()) !== -1;
};
/**
* @param {boolean=} bEncodeHtml = false
* @return {string}
*/
ContactTagModel.prototype.toLine = function (bEncodeHtml)
{
return (Utils.isUnd(bEncodeHtml) ? false : !!bEncodeHtml) ?
Utils.encodeHtml(this.name()) : this.name();
};
/** /**
* @constructor * @constructor
* @extends KnoinAbstractViewModel * @extends KnoinAbstractViewModel
@ -5205,7 +5339,7 @@ PopupsDomainViewModel.prototype.clearForm = function ()
this.smtpAuth(true); this.smtpAuth(true);
this.whiteList(''); this.whiteList('');
}; };
/** /**
* @constructor * @constructor
* @extends KnoinAbstractViewModel * @extends KnoinAbstractViewModel
@ -5342,7 +5476,7 @@ PopupsPluginViewModel.prototype.onBuild = function ()
} }
}, this)); }, this));
}; };
/** /**
* @constructor * @constructor
* @extends KnoinAbstractViewModel * @extends KnoinAbstractViewModel
@ -5458,7 +5592,7 @@ PopupsActivateViewModel.prototype.validateSubscriptionKey = function ()
{ {
var sValue = this.key(); var sValue = this.key();
return '' === sValue || !!/^RL[\d]+-[A-Z0-9\-]+Z$/.test(Utils.trim(sValue)); return '' === sValue || !!/^RL[\d]+-[A-Z0-9\-]+Z$/.test(Utils.trim(sValue));
}; };
/** /**
* @constructor * @constructor
* @extends KnoinAbstractViewModel * @extends KnoinAbstractViewModel
@ -5518,7 +5652,7 @@ PopupsLanguagesViewModel.prototype.changeLanguage = function (sLang)
RL.data().mainLanguage(sLang); RL.data().mainLanguage(sLang);
this.cancelCommand(); this.cancelCommand();
}; };
/** /**
* @constructor * @constructor
* @extends KnoinAbstractViewModel * @extends KnoinAbstractViewModel
@ -5624,7 +5758,7 @@ PopupsAskViewModel.prototype.onBuild = function ()
}, this)); }, this));
}; };
/** /**
* @constructor * @constructor
* @extends KnoinAbstractViewModel * @extends KnoinAbstractViewModel
@ -5711,7 +5845,7 @@ AdminLoginViewModel.prototype.onHide = function ()
{ {
this.loginFocus(false); this.loginFocus(false);
}; };
/** /**
* @param {?} oScreen * @param {?} oScreen
* *
@ -5735,7 +5869,7 @@ AdminMenuViewModel.prototype.link = function (sRoute)
{ {
return '#/' + sRoute; return '#/' + sRoute;
}; };
/** /**
* @constructor * @constructor
* @extends KnoinAbstractViewModel * @extends KnoinAbstractViewModel
@ -5759,7 +5893,7 @@ AdminPaneViewModel.prototype.logoutClick = function ()
RL.remote().adminLogout(function () { RL.remote().adminLogout(function () {
RL.loginAndLogoutReload(); RL.loginAndLogoutReload();
}); });
}; };
/** /**
* @constructor * @constructor
*/ */
@ -5859,7 +5993,7 @@ AdminGeneral.prototype.selectLanguage = function ()
{ {
kn.showScreenPopup(PopupsLanguagesViewModel); kn.showScreenPopup(PopupsLanguagesViewModel);
}; };
/** /**
* @constructor * @constructor
*/ */
@ -5911,7 +6045,7 @@ AdminLogin.prototype.onBuild = function ()
}, 50); }, 50);
}; };
/** /**
* @constructor * @constructor
*/ */
@ -5980,7 +6114,7 @@ AdminBranding.prototype.onBuild = function ()
}, 50); }, 50);
}; };
/** /**
* @constructor * @constructor
*/ */
@ -6200,7 +6334,7 @@ AdminContacts.prototype.onBuild = function ()
}, 50); }, 50);
}; };
/** /**
* @constructor * @constructor
*/ */
@ -6289,7 +6423,7 @@ AdminDomains.prototype.onDomainListChangeRequest = function ()
{ {
RL.reloadDomainList(); RL.reloadDomainList();
}; };
/** /**
* @constructor * @constructor
*/ */
@ -6401,7 +6535,7 @@ AdminSecurity.prototype.phpInfoLink = function ()
{ {
return RL.link().phpInfo(); return RL.link().phpInfo();
}; };
/** /**
* @constructor * @constructor
*/ */
@ -6517,7 +6651,7 @@ AdminSocial.prototype.onBuild = function ()
}, 50); }, 50);
}; };
/** /**
* @constructor * @constructor
*/ */
@ -6614,7 +6748,7 @@ AdminPlugins.prototype.onPluginDisableRequest = function (sResult, oData)
RL.reloadPluginList(); RL.reloadPluginList();
}; };
/** /**
* @constructor * @constructor
*/ */
@ -6712,7 +6846,7 @@ AdminPackages.prototype.installPackage = function (oPackage)
RL.remote().packageInstall(this.requestHelper(oPackage, true), oPackage); RL.remote().packageInstall(this.requestHelper(oPackage, true), oPackage);
} }
}; };
/** /**
* @constructor * @constructor
*/ */
@ -6763,7 +6897,7 @@ AdminLicensing.prototype.licenseExpiredMomentValue = function ()
{ {
var oDate = moment.unix(this.licenseExpired()); var oDate = moment.unix(this.licenseExpired());
return oDate.format('LL') + ' (' + oDate.from(moment()) + ')'; return oDate.format('LL') + ' (' + oDate.from(moment()) + ')';
}; };
/** /**
* @constructor * @constructor
*/ */
@ -6893,7 +7027,7 @@ AbstractData.prototype.populateDataOnStart = function()
this.contactsIsAllowed(!!RL.settingsGet('ContactsIsAllowed')); this.contactsIsAllowed(!!RL.settingsGet('ContactsIsAllowed'));
}; };
/** /**
* @constructor * @constructor
* @extends AbstractData * @extends AbstractData
@ -6935,7 +7069,7 @@ _.extend(AdminDataStorage.prototype, AbstractData.prototype);
AdminDataStorage.prototype.populateDataOnStart = function() AdminDataStorage.prototype.populateDataOnStart = function()
{ {
AbstractData.prototype.populateDataOnStart.call(this); AbstractData.prototype.populateDataOnStart.call(this);
}; };
/** /**
* @constructor * @constructor
*/ */
@ -7209,7 +7343,7 @@ AbstractAjaxRemoteStorage.prototype.jsVersion = function (fCallback, sVersion)
'Version': sVersion 'Version': sVersion
}); });
}; };
/** /**
* @constructor * @constructor
* @extends AbstractAjaxRemoteStorage * @extends AbstractAjaxRemoteStorage
@ -7454,7 +7588,7 @@ AdminAjaxRemoteStorage.prototype.adminPing = function (fCallback)
{ {
this.defaultRequest(fCallback, 'AdminPing'); this.defaultRequest(fCallback, 'AdminPing');
}; };
/** /**
* @constructor * @constructor
*/ */
@ -7537,7 +7671,7 @@ AbstractCacheStorage.prototype.setEmailsPicsHashesData = function (oData)
{ {
this.oEmailsPicsHashes = oData; this.oEmailsPicsHashes = oData;
}; };
/** /**
* @constructor * @constructor
* @extends AbstractCacheStorage * @extends AbstractCacheStorage
@ -7548,7 +7682,7 @@ function AdminCacheStorage()
} }
_.extend(AdminCacheStorage.prototype, AbstractCacheStorage.prototype); _.extend(AdminCacheStorage.prototype, AbstractCacheStorage.prototype);
/** /**
* @param {Array} aViewModels * @param {Array} aViewModels
* @constructor * @constructor
@ -7726,7 +7860,7 @@ AbstractSettings.prototype.routes = function ()
['', oRules] ['', oRules]
]; ];
}; };
/** /**
* @constructor * @constructor
* @extends KnoinAbstractScreen * @extends KnoinAbstractScreen
@ -7741,7 +7875,7 @@ _.extend(AdminLoginScreen.prototype, KnoinAbstractScreen.prototype);
AdminLoginScreen.prototype.onShow = function () AdminLoginScreen.prototype.onShow = function ()
{ {
RL.setTitle(''); RL.setTitle('');
}; };
/** /**
* @constructor * @constructor
* @extends AbstractSettings * @extends AbstractSettings
@ -7761,7 +7895,7 @@ AdminSettingsScreen.prototype.onShow = function ()
// AbstractSettings.prototype.onShow.call(this); // AbstractSettings.prototype.onShow.call(this);
RL.setTitle(''); RL.setTitle('');
}; };
/** /**
* @constructor * @constructor
* @extends KnoinAbstractBoot * @extends KnoinAbstractBoot
@ -8109,7 +8243,7 @@ AbstractApp.prototype.bootstart = function ()
ssm.ready(); ssm.ready();
}; };
/** /**
* @constructor * @constructor
* @extends AbstractApp * @extends AbstractApp
@ -8348,7 +8482,7 @@ AdminApp.prototype.bootstart = function ()
* @type {AdminApp} * @type {AdminApp}
*/ */
RL = new AdminApp(); RL = new AdminApp();
$html.addClass(Globals.bMobileDevice ? 'mobile' : 'no-mobile'); $html.addClass(Globals.bMobileDevice ? 'mobile' : 'no-mobile');
$window.keydown(Utils.killCtrlAandS).keyup(Utils.killCtrlAandS); $window.keydown(Utils.killCtrlAandS).keyup(Utils.killCtrlAandS);
@ -8399,9 +8533,9 @@ window['__RLBOOT'] = function (fCall) {
window['__RLBOOT'] = null; window['__RLBOOT'] = null;
}); });
}; };
if (window.SimplePace) { if (window.SimplePace) {
window.SimplePace.add(10); window.SimplePace.add(10);
} }
}(window, jQuery, ko, crossroads, hasher, _)); }(window, jQuery, ko, crossroads, hasher, _));

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -1,5 +1,5 @@
/** /**
* Inputosaurus Text * Inputosaurus Text
* *
* Must be instantiated on an <input> element * Must be instantiated on an <input> element
* Allows multiple input items. Each item is represented with a removable tag that appears to be inside the input area. * Allows multiple input items. Each item is represented with a removable tag that appears to be inside the input area.
@ -33,7 +33,7 @@
// //
// 'change' - triggered whenever a tag is added or removed (should be similar to binding the the change event of the instantiated input // 'change' - triggered whenever a tag is added or removed (should be similar to binding the the change event of the instantiated input
// 'keyup' - keyup event on the newly created input // 'keyup' - keyup event on the newly created input
// while typing, the user can separate values using these delimiters // while typing, the user can separate values using these delimiters
// the value tags are created on the fly when an inputDelimiter is detected // the value tags are created on the fly when an inputDelimiter is detected
inputDelimiters : [',', ';'], inputDelimiters : [',', ';'],
@ -43,6 +43,10 @@
allowDuplicates : false, allowDuplicates : false,
allowDragAndDrop : true,
focusCallback : null,
parseOnBlur : false, parseOnBlur : false,
// optional wrapper for widget // optional wrapper for widget
@ -59,7 +63,7 @@
// manipulate and return the input value after parseInput() parsing // manipulate and return the input value after parseInput() parsing
// the array of tag names is passed and expected to be returned as an array after manipulation // the array of tag names is passed and expected to be returned as an array after manipulation
parseHook : null, parseHook : null,
// define a placeholder to display when the input is empty // define a placeholder to display when the input is empty
placeholder: null placeholder: null
}, },
@ -69,36 +73,46 @@
els = {}, els = {},
o = widget.options, o = widget.options,
placeholder = o.placeholder || this.element.attr('placeholder') || null; placeholder = o.placeholder || this.element.attr('placeholder') || null;
this._chosenValues = []; this._chosenValues = [];
// Create the elements // Create the elements
els.ul = $('<ul class="inputosaurus-container"></ul>'); els.ul = $('<ul class="inputosaurus-container"></ul>');
els.ul.droppable({
'drop': function(event, ui) {
ui.draggable.addClass('inputosaurus-dropped');
els.input.val(ui.draggable.data('inputosaurus-value'));
if (ui.draggable.__widget) if (this.options.allowDragAndDrop)
{ {
ui.draggable.__widget._removeDraggedTag(ui.draggable); els.ul.droppable({
'drop': function(event, ui) {
ui.draggable.addClass('inputosaurus-dropped');
els.input.val(ui.draggable.data('inputosaurus-value'));
if (ui.draggable.__widget)
{
ui.draggable.__widget._removeDraggedTag(ui.draggable);
}
widget.parseInput();
} }
});
}
widget.parseInput(); els.input = $('<input type="text" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" />');
} // els.input = $('<input type="email" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" />');
});
els.input = $('<input type="text" />');
// els.input = $('<input type="email" />');
els.inputCont = $('<li class="inputosaurus-input inputosaurus-required"></li>'); els.inputCont = $('<li class="inputosaurus-input inputosaurus-required"></li>');
els.origInputCont = $('<li class="inputosaurus-input-hidden inputosaurus-required"></li>'); els.origInputCont = $('<li class="inputosaurus-input-hidden inputosaurus-required"></li>');
els.lastEdit = ''; els.lastEdit = '';
els.input.on('focus', function () {
widget._focusTrigger(true);
}).on('blur', function () {
widget._focusTrigger(false);
});
// define starting placeholder // define starting placeholder
if (placeholder) { if (placeholder) {
o.placeholder = placeholder; o.placeholder = placeholder;
els.input.attr('placeholder', o.placeholder); els.input.attr('placeholder', o.placeholder);
if (o.width) { if (o.width) {
els.input.css('min-width', o.width - 50); els.input.css('min-width', o.width - 50);
} }
@ -107,11 +121,11 @@
o.wrapperElement && o.wrapperElement.append(els.ul); o.wrapperElement && o.wrapperElement.append(els.ul);
this.element.replaceWith(o.wrapperElement || els.ul); this.element.replaceWith(o.wrapperElement || els.ul);
els.origInputCont.append(this.element).hide(); els.origInputCont.append(this.element).hide();
els.inputCont.append(els.input); els.inputCont.append(els.input);
els.ul.append(els.inputCont); els.ul.append(els.inputCont);
els.ul.append(els.origInputCont); els.ul.append(els.origInputCont);
o.width && els.ul.css('width', o.width); o.width && els.ul.css('width', o.width);
this.elements = els; this.elements = els;
@ -127,6 +141,20 @@
this._instAutocomplete(); this._instAutocomplete();
}, },
_focusTriggerTimer : 0,
_focusTrigger : function (bValue) {
var widget = this;
window.clearTimeout(this._focusTriggerTimer);
this._focusTriggerTimer = window.setTimeout(function () {
widget.elements.ul[!bValue ? 'removeClass' : 'addClass']('inputosaurus-focused');
if (widget.options.focusCallback)
{
widget.options.focusCallback(bValue);
}
}, 10);
},
_instAutocomplete : function() { _instAutocomplete : function() {
if(this.options.autoCompleteSource){ if(this.options.autoCompleteSource){
var widget = this; var widget = this;
@ -264,7 +292,7 @@
widget.elements.input.width(txtWidth); widget.elements.input.width(txtWidth);
// }, 1); // }, 1);
}, },
// resets placeholder on representative input // resets placeholder on representative input
_resetPlaceholder: function () { _resetPlaceholder: function () {
var placeholder = this.options.placeholder, var placeholder = this.options.placeholder,
@ -289,7 +317,7 @@
ev.preventDefault(); ev.preventDefault();
lastTag.find('a').focus(); lastTag.find('a').focus();
} }
}, },
_editTag : function(ev) { _editTag : function(ev) {
@ -304,7 +332,7 @@
ev.preventDefault(); ev.preventDefault();
var var
oPrev = null, oPrev = null,
next = false next = false
; ;
@ -325,7 +353,7 @@
{ {
widget.elements.lastEdit = oPrev.value; widget.elements.lastEdit = oPrev.value;
} }
$li.after(widget.elements.inputCont); $li.after(widget.elements.inputCont);
widget.elements.input.val(tagName); widget.elements.input.val(tagName);
@ -488,21 +516,25 @@
// @className optional className for <li> // @className optional className for <li>
_createTag : function(name, key, obj) { _createTag : function(name, key, obj) {
if (name !== undefined && obj) { if (name !== undefined && obj) {
var var
widget = this, widget = this,
$li = $('<li data-inputosaurus="' + key + '" title="' + obj.toLine(false, false, true) + $li = $('<li data-inputosaurus="' + key + '" title="' + obj.toLine(false, false, true) +
'"><a href="javascript:void(0);" class="ficon">&#x2716;</a><span>' + '"><a href="javascript:void(0);" class="ficon">&#x2716;</a><span>' +
obj.toLine(true, false, true) + '</span></li>') obj.toLine(true, false, true) + '</span></li>')
; ;
$li.data('inputosaurus-value', obj.toLine(false, false, false)); $li.data('inputosaurus-value', obj.toLine(false, false, false));
$li.draggable({
'revert': 'invalid', if (this.options.allowDragAndDrop)
'revertDuration': 200, {
'start': function(event, ui) { $li.draggable({
ui.helper.__widget = widget; 'revert': 'invalid',
} 'revertDuration': 200,
}); 'start': function(event, ui) {
ui.helper.__widget = widget;
}
});
}
return $li; return $li;
} }
@ -594,7 +626,7 @@
values.push(val); values.push(val);
delim && (values = val.split(delim)); delim && (values = val.split(delim));
if(values.length){ if (values.length) {
this._chosenValues = []; this._chosenValues = [];
$.isFunction(this.options.parseHook) && (values = this.options.parseHook(values)); $.isFunction(this.options.parseHook) && (values = this.options.parseHook(values));
@ -607,12 +639,14 @@
}, },
_attachEvents : function() { _attachEvents : function() {
var widget = this; var widget = this;
this.elements.input.on('keyup.inputosaurus', {widget : widget}, this._inputKeypress); this.elements.input.on('keyup.inputosaurus', {widget : widget}, this._inputKeypress);
this.elements.input.on('keydown.inputosaurus', {widget : widget}, this._inputKeypress); this.elements.input.on('keydown.inputosaurus', {widget : widget}, this._inputKeypress);
this.elements.input.on('change.inputosaurus', {widget : widget}, this._inputKeypress); this.elements.input.on('change.inputosaurus', {widget : widget}, this._inputKeypress);
this.elements.input.on('focus.inputosaurus', {widget : widget}, this._inputFocus); this.elements.input.on('focus.inputosaurus', {widget : widget}, this._inputFocus);
this.options.parseOnBlur && this.elements.input.on('blur.inputosaurus', {widget : widget}, this.parseInput); this.options.parseOnBlur && this.elements.input.on('blur.inputosaurus', {widget : widget}, this.parseInput);
this.elements.ul.on('click.inputosaurus', {widget : widget}, this._focus); this.elements.ul.on('click.inputosaurus', {widget : widget}, this._focus);
@ -626,14 +660,12 @@
_destroy: function() { _destroy: function() {
this.elements.input.unbind('.inputosaurus'); this.elements.input.unbind('.inputosaurus');
this.elements.ul.replaceWith(this.element); this.elements.ul.replaceWith(this.element);
} }
}; };
$('body').append(inputosaurustext.fakeSpan); $('body').append(inputosaurustext.fakeSpan);
$.widget("ui.inputosaurus", inputosaurustext); $.widget("ui.inputosaurus", inputosaurustext);
})(jQuery); })(jQuery);

File diff suppressed because one or more lines are too long