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",

View file

@ -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) {

View file

@ -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) {
$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');
}
}); });
} }
} }

View file

@ -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),

View file

@ -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

@ -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]);

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);
@ -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

@ -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,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});

View file

@ -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;

View file

@ -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;
} }
} }

View file

@ -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;

View file

@ -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');
}); });

View file

@ -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());
}; };

View file

@ -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

View file

@ -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');
} }
} }

View file

@ -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

View file

@ -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 = '';

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

@ -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;
} }
/** /**

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

@ -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 />

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

@ -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

@ -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) {
$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');
}
}); });
} }
} }
@ -4057,14 +4140,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;
@ -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

File diff suppressed because one or more lines are too long

View file

@ -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) {
$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');
}
}); });
} }
} }
@ -4990,14 +5073,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;
@ -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) {

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -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,27 +78,37 @@
// 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'); if (this.options.allowDragAndDrop)
els.input.val(ui.draggable.data('inputosaurus-value')); {
els.ul.droppable({
'drop': function(event, ui) {
if (ui.draggable.__widget) ui.draggable.addClass('inputosaurus-dropped');
{ els.input.val(ui.draggable.data('inputosaurus-value'));
ui.draggable.__widget._removeDraggedTag(ui.draggable);
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;
@ -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,13 +524,17 @@
; ;
$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