mirror of
https://github.com/the-djmaze/snappymail.git
synced 2026-07-13 03:27:39 +03:00
Contacts tags support (unstable - step 1).
+ Small fixes
This commit is contained in:
parent
74fa12c000
commit
0ca00dec40
34 changed files with 1790 additions and 801 deletions
|
|
@ -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",
|
||||||
|
|
|
||||||
|
|
@ -974,6 +974,17 @@ RainLoopApp.prototype.getAutocomplete = function (sQuery, 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) {
|
||||||
|
|
|
||||||
|
|
@ -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) {
|
||||||
|
|
@ -586,8 +594,83 @@ ko.bindingHandlers.emailsTags = {
|
||||||
|
|
||||||
if (fValue.focusTrigger)
|
if (fValue.focusTrigger)
|
||||||
{
|
{
|
||||||
fValue.focusTrigger.subscribe(function () {
|
fValue.focusTrigger.subscribe(function (bValue) {
|
||||||
|
if (bValue)
|
||||||
|
{
|
||||||
$oEl.inputosaurus('focus');
|
$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');
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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),
|
||||||
|
|
|
||||||
|
|
@ -72,15 +72,22 @@ 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())
|
||||||
|
{
|
||||||
|
if (!this.bDisabeCloseOnEsc && Enums.EventKeyCode.Esc === oEvent.keyCode)
|
||||||
{
|
{
|
||||||
Utils.delegateRun(self, 'cancelCommand');
|
Utils.delegateRun(self, 'cancelCommand');
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
else if (Enums.EventKeyCode.Backspace === oEvent.keyCode && !Utils.inFocus())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -134,9 +134,9 @@ Knoin.prototype.buildViewModel = function (ViewModelClass, oScreen)
|
||||||
|
|
||||||
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]);
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
45
dev/Models/ContactTagModel.js
Normal file
45
dev/Models/ContactTagModel.js
Normal 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();
|
||||||
|
};
|
||||||
|
|
@ -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
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -83,6 +83,7 @@ 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});
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -177,7 +177,7 @@ 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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
|
|
||||||
.inputosaurus-container {
|
.inputosaurus-container {
|
||||||
|
|
||||||
width: 99%;
|
width: 99%;
|
||||||
line-height: 20px;
|
line-height: 20px;
|
||||||
padding: 2px;
|
padding: 2px;
|
||||||
|
|
@ -9,6 +10,12 @@
|
||||||
.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;
|
||||||
|
|
|
||||||
|
|
@ -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('');
|
||||||
|
|
@ -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,6 +186,11 @@ function MailBoxMessageViewViewModel()
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.viewHash = '';
|
||||||
|
this.scrollMessageToTop();
|
||||||
|
}
|
||||||
|
|
||||||
}, this);
|
}, this);
|
||||||
|
|
||||||
|
|
@ -202,10 +214,6 @@ 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');
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ 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);
|
||||||
|
|
||||||
|
|
@ -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) {
|
||||||
|
|
@ -291,7 +307,7 @@ function PopupsContactsViewModel()
|
||||||
}, 1000);
|
}, 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
}, sRequestUid, this.viewID(), aProperties);
|
}, sRequestUid, this.viewID(), this.viewTags(), aProperties);
|
||||||
|
|
||||||
}, function () {
|
}, function () {
|
||||||
var
|
var
|
||||||
|
|
@ -324,7 +340,7 @@ function PopupsContactsViewModel()
|
||||||
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');
|
||||||
|
|
@ -562,6 +584,7 @@ PopupsContactsViewModel.prototype.populateViewContact = function (oContact)
|
||||||
|
|
||||||
this.emptySelection(false);
|
this.emptySelection(false);
|
||||||
this.viewReadOnly(false);
|
this.viewReadOnly(false);
|
||||||
|
this.viewTags('');
|
||||||
|
|
||||||
if (oContact)
|
if (oContact)
|
||||||
{
|
{
|
||||||
|
|
@ -587,9 +610,14 @@ 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)));
|
||||||
|
|
||||||
|
|
@ -626,7 +654,8 @@ 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)
|
||||||
|
|
@ -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());
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4973,11 +4973,17 @@ class Actions
|
||||||
$iLimit = 0 > $iLimit ? 20 : $iLimit;
|
$iLimit = 0 > $iLimit ? 20 : $iLimit;
|
||||||
|
|
||||||
$iResultCount = 0;
|
$iResultCount = 0;
|
||||||
if ($this->AddressBookProvider($oAccount)->IsActive())
|
$mResult = array();
|
||||||
|
$aTags = array();
|
||||||
|
|
||||||
|
$oAbp = $this->AddressBookProvider($oAccount);
|
||||||
|
if ($oAbp->IsActive())
|
||||||
{
|
{
|
||||||
$iResultCount = 0;
|
$iResultCount = 0;
|
||||||
$mResult = $this->AddressBookProvider($oAccount)->GetContacts($oAccount->ParentEmailHelper(),
|
$mResult = $oAbp->GetContacts($oAccount->ParentEmailHelper(),
|
||||||
$iOffset, $iLimit, $sSearch, $iResultCount);
|
$iOffset, $iLimit, $sSearch, $iResultCount);
|
||||||
|
|
||||||
|
$aTags = $oAbp->GetContactTags($oAccount->ParentEmailHelper());
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->DefaultResponse(__FUNCTION__, array(
|
return $this->DefaultResponse(__FUNCTION__, array(
|
||||||
|
|
@ -4985,6 +4991,26 @@ class Actions
|
||||||
'Limit' => $iLimit,
|
'Limit' => $iLimit,
|
||||||
'Count' => $iResultCount,
|
'Count' => $iResultCount,
|
||||||
'Search' => $sSearch,
|
'Search' => $sSearch,
|
||||||
|
'List' => $mResult,
|
||||||
|
'Tags' => $aTags
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function DoContactTags()
|
||||||
|
{
|
||||||
|
$oAccount = $this->getAccountFromToken();
|
||||||
|
|
||||||
|
$mResult = false;
|
||||||
|
if ($this->AddressBookProvider($oAccount)->IsActive())
|
||||||
|
{
|
||||||
|
$mResult = $this->AddressBookProvider($oAccount)->GetContactTags($oAccount->ParentEmailHelper());
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->DefaultResponse(__FUNCTION__, array(
|
||||||
'List' => $mResult
|
'List' => $mResult
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
@ -5025,6 +5051,11 @@ class Actions
|
||||||
if ($oAddressBookProvider && $oAddressBookProvider->IsActive() && 0 < \strlen($sRequestUid))
|
if ($oAddressBookProvider && $oAddressBookProvider->IsActive() && 0 < \strlen($sRequestUid))
|
||||||
{
|
{
|
||||||
$sUid = \trim($this->GetActionParam('Uid', ''));
|
$sUid = \trim($this->GetActionParam('Uid', ''));
|
||||||
|
$sTags = \trim($this->GetActionParam('Tags', ''));
|
||||||
|
$aTags = \explode(';', $sTags);
|
||||||
|
$aTags = \array_map('trim', $aTags);
|
||||||
|
$aTags = \array_unique($aTags);
|
||||||
|
|
||||||
$oContact = null;
|
$oContact = null;
|
||||||
if (0 < \strlen($sUid))
|
if (0 < \strlen($sUid))
|
||||||
{
|
{
|
||||||
|
|
@ -5040,6 +5071,7 @@ class Actions
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$oContact->Tags = $aTags;
|
||||||
$oContact->Properties = array();
|
$oContact->Properties = array();
|
||||||
$aProperties = $this->GetActionParam('Properties', array());
|
$aProperties = $this->GetActionParam('Properties', array());
|
||||||
if (\is_array($aProperties))
|
if (\is_array($aProperties))
|
||||||
|
|
@ -6933,9 +6965,19 @@ class Actions
|
||||||
'Display' => \MailSo\Base\Utils::Utf8Clear($mResponse->Display),
|
'Display' => \MailSo\Base\Utils::Utf8Clear($mResponse->Display),
|
||||||
'ReadOnly' => $mResponse->ReadOnly,
|
'ReadOnly' => $mResponse->ReadOnly,
|
||||||
'IdPropertyFromSearch' => $mResponse->IdPropertyFromSearch,
|
'IdPropertyFromSearch' => $mResponse->IdPropertyFromSearch,
|
||||||
|
'Tags' => $this->responseObject($mResponse->Tags, $sParent, $aParameters),
|
||||||
'Properties' => $this->responseObject($mResponse->Properties, $sParent, $aParameters)
|
'Properties' => $this->responseObject($mResponse->Properties, $sParent, $aParameters)
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
else if ('RainLoop\Providers\AddressBook\Classes\Tag' === $sClassName)
|
||||||
|
{
|
||||||
|
$mResult = \array_merge($this->objectData($mResponse, $sParent, $aParameters), array(
|
||||||
|
/* @var $mResponse \RainLoop\Providers\AddressBook\Classes\Tag */
|
||||||
|
'IdContactTag' => $mResponse->IdContactTag,
|
||||||
|
'Name' => \MailSo\Base\Utils::Utf8Clear($mResponse->Name),
|
||||||
|
'ReadOnly' => $mResponse->ReadOnly
|
||||||
|
));
|
||||||
|
}
|
||||||
else if ('RainLoop\Providers\AddressBook\Classes\Property' === $sClassName)
|
else if ('RainLoop\Providers\AddressBook\Classes\Property' === $sClassName)
|
||||||
{
|
{
|
||||||
// Simple hack
|
// Simple hack
|
||||||
|
|
|
||||||
|
|
@ -224,13 +224,13 @@ abstract class PdoAbstract
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @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');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,11 @@ class Contact
|
||||||
/**
|
/**
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
|
public $Tags;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
public $ReadOnly;
|
public $ReadOnly;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -58,10 +63,10 @@ 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 = '';
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
@ -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
|
||||||
|
|
@ -704,6 +811,7 @@ 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';
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -1506,7 +1737,7 @@ SQLITEINITIAL;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return $mCache;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -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,6 +323,10 @@ 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) {
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
||||||
<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>
|
||||||
|
|
||||||
<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>
|
||||||
|
|
||||||
<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>
|
||||||
|
|
||||||
<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>
|
||||||
|
|
||||||
|
<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 />
|
||||||
|
|
|
||||||
|
|
@ -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 />
|
||||||
|
|
|
||||||
|
|
@ -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)"
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
2
rainloop/v/0.0.0/static/css/app.min.css
vendored
2
rainloop/v/0.0.0/static/css/app.min.css
vendored
File diff suppressed because one or more lines are too long
|
|
@ -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),
|
||||||
|
|
@ -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) {
|
||||||
|
|
@ -3219,8 +3227,83 @@ ko.bindingHandlers.emailsTags = {
|
||||||
|
|
||||||
if (fValue.focusTrigger)
|
if (fValue.focusTrigger)
|
||||||
{
|
{
|
||||||
fValue.focusTrigger.subscribe(function () {
|
fValue.focusTrigger.subscribe(function (bValue) {
|
||||||
|
if (bValue)
|
||||||
|
{
|
||||||
$oEl.inputosaurus('focus');
|
$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');
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -4057,15 +4140,22 @@ 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())
|
||||||
|
{
|
||||||
|
if (!this.bDisabeCloseOnEsc && Enums.EventKeyCode.Esc === oEvent.keyCode)
|
||||||
{
|
{
|
||||||
Utils.delegateRun(self, 'cancelCommand');
|
Utils.delegateRun(self, 'cancelCommand');
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
else if (Enums.EventKeyCode.Backspace === oEvent.keyCode && !Utils.inFocus())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
@ -4281,9 +4371,9 @@ Knoin.prototype.buildViewModel = function (ViewModelClass, oScreen)
|
||||||
|
|
||||||
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]);
|
||||||
|
|
@ -4911,6 +5001,50 @@ 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
|
||||||
|
|
|
||||||
8
rainloop/v/0.0.0/static/js/admin.min.js
vendored
8
rainloop/v/0.0.0/static/js/admin.min.js
vendored
File diff suppressed because one or more lines are too long
|
|
@ -1806,7 +1806,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),
|
||||||
|
|
@ -3173,11 +3173,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) {
|
||||||
|
|
@ -3223,8 +3231,83 @@ ko.bindingHandlers.emailsTags = {
|
||||||
|
|
||||||
if (fValue.focusTrigger)
|
if (fValue.focusTrigger)
|
||||||
{
|
{
|
||||||
fValue.focusTrigger.subscribe(function () {
|
fValue.focusTrigger.subscribe(function (bValue) {
|
||||||
|
if (bValue)
|
||||||
|
{
|
||||||
$oEl.inputosaurus('focus');
|
$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');
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -4990,15 +5073,22 @@ 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())
|
||||||
|
{
|
||||||
|
if (!this.bDisabeCloseOnEsc && Enums.EventKeyCode.Esc === oEvent.keyCode)
|
||||||
{
|
{
|
||||||
Utils.delegateRun(self, 'cancelCommand');
|
Utils.delegateRun(self, 'cancelCommand');
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
else if (Enums.EventKeyCode.Backspace === oEvent.keyCode && !Utils.inFocus())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
@ -5214,9 +5304,9 @@ Knoin.prototype.buildViewModel = function (ViewModelClass, oScreen)
|
||||||
|
|
||||||
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]);
|
||||||
|
|
@ -5852,6 +5942,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);
|
||||||
|
|
@ -5902,6 +5993,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']))
|
||||||
{
|
{
|
||||||
|
|
@ -5913,6 +6005,11 @@ ContactModel.prototype.parse = function (oItem)
|
||||||
}, this);
|
}, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Utils.isNonEmptyArray(oItem['Tags']))
|
||||||
|
{
|
||||||
|
this.tags = oItem['Tags'].join(';');
|
||||||
|
}
|
||||||
|
|
||||||
bResult = true;
|
bResult = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -5990,6 +6087,50 @@ function ContactPropertyModel(iType, sTypeStr, sValue, bFocused, sPlaceholder)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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
|
||||||
*/
|
*/
|
||||||
|
|
@ -9732,6 +9873,7 @@ 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);
|
||||||
|
|
||||||
|
|
@ -9752,6 +9894,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) {
|
||||||
|
|
@ -9999,7 +10156,7 @@ function PopupsContactsViewModel()
|
||||||
}, 1000);
|
}, 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
}, sRequestUid, this.viewID(), aProperties);
|
}, sRequestUid, this.viewID(), this.viewTags(), aProperties);
|
||||||
|
|
||||||
}, function () {
|
}, function () {
|
||||||
var
|
var
|
||||||
|
|
@ -10032,7 +10189,7 @@ function PopupsContactsViewModel()
|
||||||
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('');
|
||||||
});
|
});
|
||||||
|
|
@ -10093,6 +10250,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');
|
||||||
|
|
@ -10270,6 +10433,7 @@ PopupsContactsViewModel.prototype.populateViewContact = function (oContact)
|
||||||
|
|
||||||
this.emptySelection(false);
|
this.emptySelection(false);
|
||||||
this.viewReadOnly(false);
|
this.viewReadOnly(false);
|
||||||
|
this.viewTags('');
|
||||||
|
|
||||||
if (oContact)
|
if (oContact)
|
||||||
{
|
{
|
||||||
|
|
@ -10295,9 +10459,14 @@ 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)));
|
||||||
|
|
||||||
|
|
@ -10334,7 +10503,8 @@ 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)
|
||||||
|
|
@ -10351,14 +10521,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());
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -13187,6 +13369,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('');
|
||||||
|
|
@ -13219,6 +13402,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));
|
||||||
|
|
@ -13246,6 +13435,11 @@ function MailBoxMessageViewViewModel()
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.viewHash = '';
|
||||||
|
this.scrollMessageToTop();
|
||||||
|
}
|
||||||
|
|
||||||
}, this);
|
}, this);
|
||||||
|
|
||||||
|
|
@ -13269,10 +13463,6 @@ 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');
|
||||||
});
|
});
|
||||||
|
|
@ -15260,6 +15450,7 @@ 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});
|
||||||
|
|
@ -17390,11 +17581,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
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
@ -19612,6 +19804,17 @@ RainLoopApp.prototype.getAutocomplete = function (sQuery, 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) {
|
||||||
|
|
|
||||||
18
rainloop/v/0.0.0/static/js/app.min.js
vendored
18
rainloop/v/0.0.0/static/js/app.min.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
42
vendors/inputosaurus/inputosaurus.js
vendored
42
vendors/inputosaurus/inputosaurus.js
vendored
|
|
@ -43,6 +43,10 @@
|
||||||
|
|
||||||
allowDuplicates : false,
|
allowDuplicates : false,
|
||||||
|
|
||||||
|
allowDragAndDrop : true,
|
||||||
|
|
||||||
|
focusCallback : null,
|
||||||
|
|
||||||
parseOnBlur : false,
|
parseOnBlur : false,
|
||||||
|
|
||||||
// optional wrapper for widget
|
// optional wrapper for widget
|
||||||
|
|
@ -74,6 +78,9 @@
|
||||||
|
|
||||||
// Create the elements
|
// Create the elements
|
||||||
els.ul = $('<ul class="inputosaurus-container"></ul>');
|
els.ul = $('<ul class="inputosaurus-container"></ul>');
|
||||||
|
|
||||||
|
if (this.options.allowDragAndDrop)
|
||||||
|
{
|
||||||
els.ul.droppable({
|
els.ul.droppable({
|
||||||
'drop': function(event, ui) {
|
'drop': function(event, ui) {
|
||||||
|
|
||||||
|
|
@ -88,13 +95,20 @@
|
||||||
widget.parseInput();
|
widget.parseInput();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
els.input = $('<input type="text" />');
|
els.input = $('<input type="text" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" />');
|
||||||
// els.input = $('<input type="email" />');
|
// els.input = $('<input type="email" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" />');
|
||||||
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;
|
||||||
|
|
@ -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;
|
||||||
|
|
@ -496,6 +524,9 @@
|
||||||
;
|
;
|
||||||
|
|
||||||
$li.data('inputosaurus-value', obj.toLine(false, false, false));
|
$li.data('inputosaurus-value', obj.toLine(false, false, false));
|
||||||
|
|
||||||
|
if (this.options.allowDragAndDrop)
|
||||||
|
{
|
||||||
$li.draggable({
|
$li.draggable({
|
||||||
'revert': 'invalid',
|
'revert': 'invalid',
|
||||||
'revertDuration': 200,
|
'revertDuration': 200,
|
||||||
|
|
@ -503,6 +534,7 @@
|
||||||
ui.helper.__widget = widget;
|
ui.helper.__widget = widget;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return $li;
|
return $li;
|
||||||
}
|
}
|
||||||
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
||||||
2
vendors/inputosaurus/inputosaurus.min.js
vendored
2
vendors/inputosaurus/inputosaurus.min.js
vendored
File diff suppressed because one or more lines are too long
Loading…
Add table
Add a link
Reference in a new issue