Add pagenator to contact list

Move contacts from plugin back to core
This commit is contained in:
RainLoop Team 2013-12-08 03:58:33 +04:00
parent daa958ed44
commit 0ec4fc89d4
44 changed files with 1250 additions and 889 deletions

View file

@ -67,11 +67,6 @@
<param name="plugin-name" value="ispmanager-change-password"/> <param name="plugin-name" value="ispmanager-change-password"/>
</antcall> </antcall>
</target> </target>
<target name="personal-address-book-mysql">
<antcall target="_build_plugin_">
<param name="plugin-name" value="personal-address-book-mysql"/>
</antcall>
</target>
<target name="black-list"> <target name="black-list">
<antcall target="_build_plugin_"> <antcall target="_build_plugin_">
<param name="plugin-name" value="black-list"/> <param name="plugin-name" value="black-list"/>

View file

@ -10,6 +10,12 @@ Consts.DataImages = {};
*/ */
Consts.Defaults.MessagesPerPage = 20; Consts.Defaults.MessagesPerPage = 20;
/**
* @const
* @type {number}
*/
Consts.Defaults.ContactsPerPage = 20;
/** /**
* @const * @const
* @type {Array} * @type {Array}

View file

@ -1342,3 +1342,117 @@ Utils.resizeAndCrop = function (sUrl, iValue, fCallback)
oTempImg.src = sUrl; oTempImg.src = sUrl;
}; };
Utils.computedPagenatorHelper = function (koCurrentPage, koPageCount) {
return function() {
var
iPrev = 0,
iNext = 0,
iLimit = 2,
aResult = [],
iCurrentPage = koCurrentPage(),
iPageCount = koPageCount(),
/**
* @param {number} iIndex
* @param {boolean=} bPush
* @param {string=} sCustomName
*/
fAdd = function (iIndex, bPush, sCustomName) {
var oData = {
'current': iIndex === iCurrentPage,
'name': Utils.isUnd(sCustomName) ? iIndex.toString() : sCustomName.toString(),
'custom': Utils.isUnd(sCustomName) ? false : true,
'title': Utils.isUnd(sCustomName) ? '' : iIndex.toString(),
'value': iIndex.toString()
};
if (Utils.isUnd(bPush) ? true : !!bPush)
{
aResult.push(oData);
}
else
{
aResult.unshift(oData);
}
}
;
if (1 < iPageCount || (0 < iPageCount && iPageCount < iCurrentPage))
// if (0 < iPageCount && 0 < iCurrentPage)
{
if (iPageCount < iCurrentPage)
{
fAdd(iPageCount);
iPrev = iPageCount;
iNext = iPageCount;
}
else
{
if (3 >= iCurrentPage || iPageCount - 2 <= iCurrentPage)
{
iLimit += 2;
}
fAdd(iCurrentPage);
iPrev = iCurrentPage;
iNext = iCurrentPage;
}
while (0 < iLimit) {
iPrev -= 1;
iNext += 1;
if (0 < iPrev)
{
fAdd(iPrev, false);
iLimit--;
}
if (iPageCount >= iNext)
{
fAdd(iNext, true);
iLimit--;
}
else if (0 >= iPrev)
{
break;
}
}
if (3 === iPrev)
{
fAdd(2, false);
}
else if (3 < iPrev)
{
fAdd(Math.round((iPrev - 1) / 2), false, '...');
}
if (iPageCount - 2 === iNext)
{
fAdd(iPageCount - 1, true);
}
else if (iPageCount - 2 > iNext)
{
fAdd(Math.round((iPageCount + iNext) / 2), true, '...');
}
// first and last
if (1 < iPrev)
{
fAdd(1, false);
}
if (iPageCount > iNext)
{
fAdd(iPageCount, true);
}
}
return aResult;
};
};

View file

@ -187,7 +187,7 @@ function WebMailDataStorage()
this.messageListPageCount = ko.computed(function () { this.messageListPageCount = ko.computed(function () {
var iPage = Math.ceil(this.messageListCount() / this.messagesPerPage()); var iPage = Math.ceil(this.messageListCount() / this.messagesPerPage());
return 0 === iPage ? 1 : iPage; return 0 >= iPage ? 1 : iPage;
}, this); }, this);
this.mainMessageListSearch = ko.computed({ this.mainMessageListSearch = ko.computed({

View file

@ -1,5 +1,5 @@
@contacts-popup-left-width: 250px; @contacts-popup-left-width: 270px;
.b-contacts-content { .b-contacts-content {
@ -58,13 +58,28 @@
.e-search { .e-search {
margin-top: 7px; margin-top: 7px;
width: @contacts-popup-left-width - 25;
}
}
.b-list-footer-toopbar {
position: absolute;
left: 0;
bottom: 0;
height: 105px;
width: @contacts-popup-left-width;
background-color: #eee;
.box-shadow(inset 0 1px 0 #ccc);
.footer-pager {
padding: 8px 10px 0 0;
} }
} }
.b-list-content { .b-list-content {
position: absolute; position: absolute;
top: 45px; top: 45px;
bottom: 60px; bottom: 105px;
left: 0; left: 0;
width: @contacts-popup-left-width; width: @contacts-popup-left-width;
overflow: hidden; overflow: hidden;
@ -81,6 +96,7 @@
font-size: 14px; font-size: 14px;
line-height: 13px; line-height: 13px;
background-color: #fff; background-color: #fff;
.box-shadow(inset 0 -1px 0 #ccc);
} }
.listEmptyList, .listEmptyListLoading, .listEmptySearchList { .listEmptyList, .listEmptyListLoading, .listEmptySearchList {

View file

@ -485,29 +485,6 @@ html.rl-no-preview-pane {
margin-right: 10px !important; margin-right: 10px !important;
} }
} }
.pagenator {
.page {
display: inline-block;
color: #999;
text-decoration: none;
font-size: 24px;
padding: 3px;
cursor: pointer;
&:hover .pageNumber {
color: #555;
}
&.current .pageNumber {
font-size: 28px;
color: #333;
border-bottom: 2px solid #000;
}
}
}
} }
.draggablePlace { .draggablePlace {

View file

@ -256,6 +256,13 @@ html.rl-no-preview-pane {
.b-text-part { .b-text-part {
div[data-x-div-type=html] {
height: 100%;
div[data-x-div-type=html] {
height: 100%;
}
}
a { a {
color: blue; color: blue;
text-decoration: underline; text-decoration: underline;

View file

@ -80,11 +80,38 @@
} }
} }
.g-ui-height-100proc {
height: 100%;
}
.g-ui-resizable-delimiter-highlight { .g-ui-resizable-delimiter-highlight {
border: none; border: none;
border-right: 6px solid #aaa; border-right: 6px solid #aaa;
} }
.e-pagenator {
.e-page {
display: inline-block;
color: #999;
text-decoration: none;
font-size: 24px;
padding: 3px;
cursor: pointer;
&:hover .e-page-number {
color: #555;
}
&.current .e-page-number {
font-size: 28px;
color: #333;
border-bottom: 2px solid #000;
}
}
}
html.rgba .g-ui-resizable-delimiter-highlight { html.rgba .g-ui-resizable-delimiter-highlight {
border-right-color: rgba(0, 0, 0, 0.2); border-right-color: rgba(0, 0, 0, 0.2);
} }

View file

@ -56,118 +56,7 @@ function MailBoxMessageListViewModel()
return '' === sValue ? '' : Utils.i18n('MESSAGE_LIST/SEARCH_RESULT_FOR', {'SEARCH': sValue}); return '' === sValue ? '' : Utils.i18n('MESSAGE_LIST/SEARCH_RESULT_FOR', {'SEARCH': sValue});
}); });
this.messageListPagenator = ko.computed(function () { this.messageListPagenator = ko.computed(Utils.computedPagenatorHelper(oData.messageListPage, oData.messageListPageCount));
var
iPrev = 0,
iNext = 0,
iLimit = 2,
aResult = [],
iCurrentPage = oData.messageListPage(),
iPageCount = oData.messageListPageCount(),
/**
* @param {number} iIndex
* @param {boolean=} bPush
* @param {string=} sCustomName
*/
fAdd = function (iIndex, bPush, sCustomName) {
var oData = {
'current': iIndex === iCurrentPage,
'name': Utils.isUnd(sCustomName) ? iIndex.toString() : sCustomName.toString(),
'custom': Utils.isUnd(sCustomName) ? false : true,
'title': Utils.isUnd(sCustomName) ? '' : iIndex.toString(),
'value': iIndex.toString()
};
if (Utils.isUnd(bPush) ? true : !!bPush)
{
aResult.push(oData);
}
else
{
aResult.unshift(oData);
}
}
;
if (1 < iPageCount || (0 < iPageCount && iPageCount < iCurrentPage))
// if (0 < iPageCount && 0 < iCurrentPage)
{
if (iPageCount < iCurrentPage)
{
fAdd(iPageCount);
iPrev = iPageCount;
iNext = iPageCount;
}
else
{
if (3 >= iCurrentPage || iPageCount - 2 <= iCurrentPage)
{
iLimit += 2;
}
fAdd(iCurrentPage);
iPrev = iCurrentPage;
iNext = iCurrentPage;
}
while (0 < iLimit) {
iPrev -= 1;
iNext += 1;
if (0 < iPrev)
{
fAdd(iPrev, false);
iLimit--;
}
if (iPageCount >= iNext)
{
fAdd(iNext, true);
iLimit--;
}
else if (0 >= iPrev)
{
break;
}
}
if (3 === iPrev)
{
fAdd(2, false);
}
else if (3 < iPrev)
{
fAdd(Math.round((iPrev - 1) / 2), false, '...');
}
if (iPageCount - 2 === iNext)
{
fAdd(iPageCount - 1, true);
}
else if (iPageCount - 2 > iNext)
{
fAdd(Math.round((iPageCount + iNext) / 2), true, '...');
}
// first and last
if (1 < iPrev)
{
fAdd(1, false);
}
if (iPageCount > iNext)
{
fAdd(iPageCount, true);
}
}
return aResult;
}, this);
this.checkAll = ko.computed({ this.checkAll = ko.computed({
'read': function () { 'read': function () {
@ -804,7 +693,7 @@ MailBoxMessageListViewModel.prototype.onBuild = function (oDom)
}); });
oDom oDom
.on('click', '.pagenator .page', function () { .on('click', '.e-pagenator .e-page', function () {
var oPage = ko.dataFor(this); var oPage = ko.dataFor(this);
if (oPage) if (oPage)
{ {

View file

@ -25,10 +25,19 @@ function PopupsContactsViewModel()
; ;
this.search = ko.observable(''); this.search = ko.observable('');
this.contactsCount = ko.observable(0);
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.currentContact = ko.observable(null); this.currentContact = ko.observable(null);
this.contactsPage = ko.observable(1);
this.contactsPageCount = ko.computed(function () {
var iPage = Math.ceil(this.contactsCount() / Consts.Defaults.ContactsPerPage);
return 0 >= iPage ? 1 : iPage;
}, this);
this.contactsPagenator = ko.computed(Utils.computedPagenatorHelper(this.contactsPage, this.contactsPageCount));
this.emptySelection = ko.observable(true); this.emptySelection = ko.observable(true);
this.viewClearSearch = ko.observable(false); this.viewClearSearch = ko.observable(false);
@ -225,28 +234,24 @@ function PopupsContactsViewModel()
var bV = this.viewHasNonEmptyRequaredProperties(); var bV = this.viewHasNonEmptyRequaredProperties();
return !this.viewSaving() && bV; return !this.viewSaving() && bV;
}); });
this.bDropPageAfterDelete = false;
} }
Utils.extendAsViewModel('PopupsContactsViewModel', PopupsContactsViewModel); Utils.extendAsViewModel('PopupsContactsViewModel', PopupsContactsViewModel);
PopupsContactsViewModel.prototype.addNewEmail = function () PopupsContactsViewModel.prototype.addNewEmail = function ()
{ {
// if (0 === this.viewPropertiesEmailsEmpty().length)
// {
var oItem = new ContactPropertyModel(Enums.ContactPropertyType.EmailPersonal, ''); var oItem = new ContactPropertyModel(Enums.ContactPropertyType.EmailPersonal, '');
oItem.focused(true); oItem.focused(true);
this.viewProperties.push(oItem); this.viewProperties.push(oItem);
// }
}; };
PopupsContactsViewModel.prototype.addNewPhone = function () PopupsContactsViewModel.prototype.addNewPhone = function ()
{ {
// if (0 === this.viewPropertiesPhonesEmpty().length)
// {
var oItem = new ContactPropertyModel(Enums.ContactPropertyType.PhonePersonal, ''); var oItem = new ContactPropertyModel(Enums.ContactPropertyType.PhonePersonal, '');
oItem.focused(true); oItem.focused(true);
this.viewProperties.push(oItem); this.viewProperties.push(oItem);
// }
}; };
PopupsContactsViewModel.prototype.removeCheckedOrSelectedContactsFromList = function () PopupsContactsViewModel.prototype.removeCheckedOrSelectedContactsFromList = function ()
@ -255,6 +260,7 @@ PopupsContactsViewModel.prototype.removeCheckedOrSelectedContactsFromList = func
self = this, self = this,
oKoContacts = this.contacts, oKoContacts = this.contacts,
oCurrentContact = this.currentContact(), oCurrentContact = this.currentContact(),
iCount = this.contacts().length,
aContacts = this.contactsCheckedOrSelected() aContacts = this.contactsCheckedOrSelected()
; ;
@ -269,8 +275,14 @@ PopupsContactsViewModel.prototype.removeCheckedOrSelectedContactsFromList = func
} }
oContact.deleted(true); oContact.deleted(true);
iCount--;
}); });
if (iCount <= 0)
{
this.bDropPageAfterDelete = true;
}
_.delay(function () { _.delay(function () {
_.each(aContacts, function (oContact) { _.each(aContacts, function (oContact) {
@ -302,13 +314,13 @@ PopupsContactsViewModel.prototype.deleteResponse = function (sResult, oData)
{ {
if (500 < (Enums.StorageResultType.Success === sResult && oData && oData.Time ? Utils.pInt(oData.Time) : 0)) if (500 < (Enums.StorageResultType.Success === sResult && oData && oData.Time ? Utils.pInt(oData.Time) : 0))
{ {
this.reloadContactList(); this.reloadContactList(this.bDropPageAfterDelete);
} }
else else
{ {
_.delay((function (self) { _.delay((function (self) {
return function () { return function () {
self.reloadContactList(); self.reloadContactList(self.bDropPageAfterDelete);
}; };
}(this)), 500); }(this)), 500);
} }
@ -361,12 +373,31 @@ PopupsContactsViewModel.prototype.populateViewContact = function (oContact)
this.viewProperties(aList); this.viewProperties(aList);
}; };
PopupsContactsViewModel.prototype.reloadContactList = function () /**
* @param {boolean=} bDropPagePosition = false
*/
PopupsContactsViewModel.prototype.reloadContactList = function (bDropPagePosition)
{ {
var self = this; var
self = this,
iOffset = (this.contactsPage() - 1) * Consts.Defaults.ContactsPerPage
;
this.bDropPageAfterDelete = false;
if (Utils.isUnd(bDropPagePosition) ? false : !!bDropPagePosition)
{
this.contactsPage(1);
iOffset = 0;
}
this.contacts.loading(true); this.contacts.loading(true);
RL.remote().contacts(function (sResult, oData) { RL.remote().contacts(function (sResult, oData) {
var aList = []; var
iCount = 0,
aList = []
;
if (Enums.StorageResultType.Success === sResult && oData && oData.Result && oData.Result.List) if (Enums.StorageResultType.Success === sResult && oData && oData.Result && oData.Result.List)
{ {
if (Utils.isNonEmptyArray(oData.Result.List)) if (Utils.isNonEmptyArray(oData.Result.List))
@ -377,9 +408,14 @@ PopupsContactsViewModel.prototype.reloadContactList = function ()
}); });
aList = _.compact(aList); aList = _.compact(aList);
iCount = Utils.pInt(oData.Result.Count);
iCount = 0 < iCount ? iCount : 0;
} }
} }
self.contactsCount(iCount);
self.contacts(aList); self.contacts(aList);
self.viewClearSearch('' !== self.search()); self.viewClearSearch('' !== self.search());
self.contacts.loading(false); self.contacts.loading(false);
@ -389,7 +425,7 @@ PopupsContactsViewModel.prototype.reloadContactList = function ()
self.contacts.setSelectedByUid('' + self.viewID()); self.contacts.setSelectedByUid('' + self.viewID());
} }
}, 0, 20, this.search()); }, iOffset, Consts.Defaults.ContactsPerPage, this.search());
}; };
PopupsContactsViewModel.prototype.onBuild = function (oDom) PopupsContactsViewModel.prototype.onBuild = function (oDom)
@ -399,6 +435,8 @@ PopupsContactsViewModel.prototype.onBuild = function (oDom)
this.selector.init(this.oContentVisible, this.oContentScrollable); this.selector.init(this.oContentVisible, this.oContentScrollable);
var self = this;
ko.computed(function () { ko.computed(function () {
var var
bModalVisibility = this.modalVisibility(), bModalVisibility = this.modalVisibility(),
@ -406,12 +444,23 @@ PopupsContactsViewModel.prototype.onBuild = function (oDom)
; ;
this.selector.useKeyboard(bModalVisibility && bUseKeyboardShortcuts); this.selector.useKeyboard(bModalVisibility && bUseKeyboardShortcuts);
}, this).extend({'notify': 'always'}); }, this).extend({'notify': 'always'});
oDom
.on('click', '.e-pagenator .e-page', function () {
var oPage = ko.dataFor(this);
if (oPage)
{
self.contactsPage(Utils.pInt(oPage.value));
self.reloadContactList();
}
})
;
}; };
PopupsContactsViewModel.prototype.onShow = function () PopupsContactsViewModel.prototype.onShow = function ()
{ {
kn.routeOff(); kn.routeOff();
this.reloadContactList(); this.reloadContactList(true);
}; };
PopupsContactsViewModel.prototype.onHide = function () PopupsContactsViewModel.prototype.onHide = function ()

View file

@ -1,20 +0,0 @@
The MIT License (MIT)
Copyright (c) 2013 RainLoop Team
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View file

@ -1 +0,0 @@
Personal addressbook plugin (MySQL)

View file

@ -1 +0,0 @@
1.0

View file

@ -1,70 +0,0 @@
<?php
class PersonalAddressBookMysqlPlugin extends \RainLoop\Plugins\AbstractPlugin
{
/**
* @return void
*/
public function Init()
{
$this->addHook('main.fabrica', 'MainFabrica');
}
/**
* @return string
*/
public function Supported()
{
if (!extension_loaded('pdo') || !class_exists('PDO'))
{
return 'The PHP exention PDO (mysql) must be installed to use this plugin';
}
$aDrivers = \PDO::getAvailableDrivers();
if (!is_array($aDrivers) || !in_array('mysql', $aDrivers))
{
return 'The PHP exention PDO (mysql) must be installed to use this plugin';
}
return '';
}
/**
* @param string $sName
* @param mixed $oProvider
*/
public function MainFabrica($sName, &$oProvider)
{
if (!$oProvider && 'personal-address-book' === $sName &&
$this->Config()->Get('plugin', 'enabled', false))
{
$sDsn = \trim($this->Config()->Get('plugin', 'pdo_dsn', ''));
$sUser = \trim($this->Config()->Get('plugin', 'user', ''));
$sPassword = (string) $this->Config()->Get('plugin', 'password', '');
include_once __DIR__.'/MySqlPersonalAddressBookDriver.php';
$oProvider = new MySqlPersonalAddressBookDriver($sDsn, $sUser, $sPassword);
$oProvider->SetLogger($this->Manager()->Actions()->Logger());
}
}
/**
* @return array
*/
public function configMapping()
{
return array(
\RainLoop\Plugins\Property::NewInstance('enabled')->SetLabel('Enable')
->SetType(\RainLoop\Enumerations\PluginPropertyType::BOOL)
->SetDefaultValue(false),
\RainLoop\Plugins\Property::NewInstance('pdo_dsn')->SetLabel('PDO dsn')
->SetDefaultValue('mysql:host=127.0.0.1;port=3306;dbname=rainloop'),
\RainLoop\Plugins\Property::NewInstance('user')->SetLabel('DB User')
->SetDefaultValue('root'),
\RainLoop\Plugins\Property::NewInstance('password')->SetLabel('DB Password')
->SetType(\RainLoop\Enumerations\PluginPropertyType::PASSWORD)
->SetDefaultValue('')
);
}
}

View file

@ -1,82 +0,0 @@
/*!40014 SET FOREIGN_KEY_CHECKS=0 */;
-- rainloop_system --
CREATE TABLE IF NOT EXISTS `rainloop_system` (
`sys_name` varchar(50) NOT NULL,
`value_int` int(11) UNSIGNED NOT NULL DEFAULT '0',
`value_str` varchar(255) NOT NULL DEFAULT ''
) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */;
-- rainloop_users --
CREATE TABLE IF NOT EXISTS `rainloop_users` (
`id_user` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`rl_email` varchar(255) NOT NULL,
UNIQUE `email_unique` (`rl_email`),
PRIMARY KEY(`id_user`)
) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET ascii COLLATE ascii_general_ci */;
-- rainloop_pab_contacts --
CREATE TABLE IF NOT EXISTS `rainloop_pab_contacts` (
`id_contact` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`id_user` int(11) UNSIGNED NOT NULL,
`display` varchar(255) NOT NULL DEFAULT '',
`display_name` varchar(255) NOT NULL DEFAULT '',
`display_email` varchar(255) NOT NULL DEFAULT '',
`auto` int(1) UNSIGNED NOT NULL DEFAULT '0',
`changed` int(11) UNSIGNED NOT NULL DEFAULT '0',
PRIMARY KEY(`id_contact`),
CONSTRAINT `id_user_fk_rainloop_pab_contacts` FOREIGN KEY (`id_user`)
REFERENCES `rainloop_users` (`id_user`) ON DELETE CASCADE ON UPDATE CASCADE
) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */;
-- rainloop_pab_prop --
CREATE TABLE IF NOT EXISTS `rainloop_pab_prop` (
`id_prop` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`id_contact` int(11) UNSIGNED NOT NULL,
`id_user` int(11) UNSIGNED NOT NULL,
`type` int(11) UNSIGNED NOT NULL,
`type_custom` varchar(50) /*!40101 CHARACTER SET ascii COLLATE ascii_general_ci */ NOT NULL DEFAULT '',
`value` varchar(255) NOT NULL DEFAULT '',
`value_custom` varchar(255) NOT NULL DEFAULT '',
`frec` int(11) UNSIGNED NOT NULL DEFAULT '0',
PRIMARY KEY(`id_prop`),
INDEX `id_user_id_contact_index` (`id_user`, `id_contact`),
INDEX `id_user_value_index` (`id_user`, `value`),
CONSTRAINT `id_contact_fk_rainloop_pab_prop` FOREIGN KEY (`id_contact`)
REFERENCES `rainloop_pab_contacts` (`id_contact`) ON DELETE CASCADE ON UPDATE CASCADE
) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */;
-- rainloop_pab_tags --
CREATE TABLE IF NOT EXISTS `rainloop_pab_tags` (
`id_tag` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`id_user` int(11) UNSIGNED NOT NULL,
`name` varchar(255) NOT NULL,
PRIMARY KEY(`id_tag`),
UNIQUE `id_user_name_unique` (`id_user`, `name`),
CONSTRAINT `id_user_fk_rainloop_pab_tags` FOREIGN KEY (`id_user`)
REFERENCES `rainloop_users` (`id_user`) ON DELETE CASCADE ON UPDATE CASCADE
) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */;
-- rainloop_pab_tags_contacts --
CREATE TABLE IF NOT EXISTS `rainloop_pab_tags_contacts` (
`id_tag` int(11) UNSIGNED NOT NULL,
`id_contact` int(11) UNSIGNED NOT NULL,
CONSTRAINT `id_contact_fk_rainloop_tags_contacts` FOREIGN KEY (`id_contact`)
REFERENCES `rainloop_pab_contacts` (`id_contact`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `id_tag_fk_rainloop_tags_contacts` FOREIGN KEY (`id_tag`)
REFERENCES `rainloop_pab_tags` (`id_tag`) ON DELETE CASCADE ON UPDATE CASCADE
) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */;
/*!40014 SET FOREIGN_KEY_CHECKS=1 */;

View file

@ -196,7 +196,10 @@ class Actions
private function fabrica($sName, $oAccount = null) private function fabrica($sName, $oAccount = null)
{ {
$oResult = null; $oResult = null;
$this->Plugins()->RunHook('main.fabrica', array($sName, &$oResult), false); $this->Plugins()
->RunHook('main.fabrica', array($sName, &$oResult), false)
->RunHook('main.fabrica[v2]', array($sName, &$oResult, &$oAccount), false)
;
if (null === $oResult) if (null === $oResult)
{ {
@ -225,6 +228,15 @@ class Actions
break; break;
case 'personal-address-book': case 'personal-address-book':
// \RainLoop\Providers\PersonalAddressBook\PersonalAddressBookInterface // \RainLoop\Providers\PersonalAddressBook\PersonalAddressBookInterface
if ($this->Config()->Get('contacts', 'enable', false))
{
$sDsn = \trim($this->Config()->Get('contacts', 'pdo_dsn', ''));
$sUser = \trim($this->Config()->Get('contacts', 'pdo_user', ''));
$sPassword = (string) $this->Config()->Get('contacts', 'pdo_password', '');
$oResult = new \RainLoop\Providers\PersonalAddressBook\MySqlPersonalAddressBook($sDsn, $sUser, $sPassword);
$oResult->SetLogger($this->Logger());
}
break; break;
case 'suggestions': case 'suggestions':
// \RainLoop\Providers\Suggestions\SuggestionsInterface // \RainLoop\Providers\Suggestions\SuggestionsInterface
@ -3973,13 +3985,15 @@ class Actions
if ($this->PersonalAddressBookProvider($oAccount)->IsActive()) if ($this->PersonalAddressBookProvider($oAccount)->IsActive())
{ {
$iCount = 0;
$mResult = $this->PersonalAddressBookProvider($oAccount)->GetContacts($oAccount, $mResult = $this->PersonalAddressBookProvider($oAccount)->GetContacts($oAccount,
$iOffset, $iLimit, $sSearch, false); $iOffset, $iLimit, $sSearch, false, $iCount);
} }
return $this->DefaultResponse(__FUNCTION__, array( return $this->DefaultResponse(__FUNCTION__, array(
'Offset' => $iOffset, 'Offset' => $iOffset,
'Limit' => $iLimit, 'Limit' => $iLimit,
'Count' => $iCount,
'Search' => $sSearch, 'Search' => $sSearch,
'List' => $mResult 'List' => $mResult
)); ));
@ -4012,6 +4026,8 @@ class Actions
*/ */
public function DoContactSave() public function DoContactSave()
{ {
$iStart = \time();
$oAccount = $this->getAccountFromToken(); $oAccount = $this->getAccountFromToken();
$bResult = false; $bResult = false;
@ -4048,6 +4064,11 @@ class Actions
$bResult = $oPab->ContactSave($oAccount, $oContact); $bResult = $oPab->ContactSave($oAccount, $oContact);
} }
if (\time() === $iStart)
{
sleep(1);
}
return $this->DefaultResponse(__FUNCTION__, array( return $this->DefaultResponse(__FUNCTION__, array(
'RequestUid' => $sRequestUid, 'RequestUid' => $sRequestUid,
'ResultID' => $bResult ? $oContact->IdContact : '', 'ResultID' => $bResult ? $oContact->IdContact : '',
@ -5608,6 +5629,7 @@ class Actions
/* @var $mResponse \RainLoop\Providers\PersonalAddressBook\Classes\Contact */ /* @var $mResponse \RainLoop\Providers\PersonalAddressBook\Classes\Contact */
'IdContact' => $mResponse->IdContact, 'IdContact' => $mResponse->IdContact,
'Display' => \MailSo\Base\Utils::Utf8Clear($mResponse->Display), 'Display' => \MailSo\Base\Utils::Utf8Clear($mResponse->Display),
'IdPropertyFromSearch' => $mResponse->IdPropertyFromSearch,
'Properties' => $this->responseObject($mResponse->Properties, $sParent, $aParameters) 'Properties' => $this->responseObject($mResponse->Properties, $sParent, $aParameters)
)); ));
} }
@ -5615,6 +5637,7 @@ class Actions
{ {
$mResult = \array_merge($this->objectData($mResponse, $sParent, $aParameters), array( $mResult = \array_merge($this->objectData($mResponse, $sParent, $aParameters), array(
/* @var $mResponse \RainLoop\Providers\PersonalAddressBook\Classes\Property */ /* @var $mResponse \RainLoop\Providers\PersonalAddressBook\Classes\Property */
'IdProperty' => $mResponse->IdProperty,
'Type' => $mResponse->Type, 'Type' => $mResponse->Type,
'TypeCustom' => $mResponse->TypeCustom, 'TypeCustom' => $mResponse->TypeCustom,
'Value' => \MailSo\Base\Utils::Utf8Clear($mResponse->Value), 'Value' => \MailSo\Base\Utils::Utf8Clear($mResponse->Value),

View file

@ -9,6 +9,11 @@ abstract class PdoAbstract
*/ */
protected $oPDO = null; protected $oPDO = null;
/**
* @var bool
*/
protected $bExplain = false;
/** /**
* @var \MailSo\Log\Logger * @var \MailSo\Log\Logger
*/ */
@ -130,22 +135,26 @@ abstract class PdoAbstract
} }
/** /**
* @param \RainLoop\Account $oAccount
* @param string $sSql * @param string $sSql
* @param array $aParams * @param array $aParams
* @param bool $bMultParams = false * @param bool $bMultiplyParams = false
* *
* @return \PDOStatement|null * @return \PDOStatement|null
*/ */
protected function prepareAndExecute($sSql, $aParams = array(), $bMultParams = false) protected function prepareAndExecute($sSql, $aParams = array(), $bMultiplyParams = false)
{ {
if ($this->bExplain && !$bMultiplyParams)
{
$this->prepareAndExplain($sSql, $aParams);
}
$mResult = null; $mResult = null;
$this->writeLog($sSql); $this->writeLog($sSql);
$oStmt = $this->getPDO()->prepare($sSql); $oStmt = $this->getPDO()->prepare($sSql);
if ($oStmt) if ($oStmt)
{ {
$aRootParams = $bMultParams ? $aParams : array($aParams); $aRootParams = $bMultiplyParams ? $aParams : array($aParams);
foreach ($aRootParams as $aSubParams) foreach ($aRootParams as $aSubParams)
{ {
foreach ($aSubParams as $sName => $aValue) foreach ($aSubParams as $sName => $aValue)
@ -153,13 +162,46 @@ abstract class PdoAbstract
$oStmt->bindValue($sName, $aValue[0], $aValue[1]); $oStmt->bindValue($sName, $aValue[0], $aValue[1]);
} }
$mResult = $oStmt->execute() && !$bMultParams ? $oStmt : null; $mResult = $oStmt->execute() && !$bMultiplyParams ? $oStmt : null;
} }
} }
return $mResult; return $mResult;
} }
/**
* @param string $sSql
* @param array $aParams
*/
protected function prepareAndExplain($sSql, $aParams = array())
{
$mResult = null;
if (0 === strpos($sSql, 'SELECT '))
{
$sSql = 'EXPLAIN '.$sSql;
$this->writeLog($sSql);
$oStmt = $this->getPDO()->prepare($sSql);
if ($oStmt)
{
foreach ($aParams as $sName => $aValue)
{
$oStmt->bindValue($sName, $aValue[0], $aValue[1]);
}
$mResult = $oStmt->execute() ? $oStmt : null;
}
}
if ($mResult)
{
$aFetch = $mResult->fetchAll(\PDO::FETCH_ASSOC);
$this->oLogger->WriteDump($aFetch);
unset($aFetch);
$mResult->closeCursor();
}
}
/** /**
* @param string $sSql * @param string $sSql
*/ */

View file

@ -81,6 +81,14 @@ class Application extends \RainLoop\Config\AbstractConfig
0 for unlimited.') 0 for unlimited.')
), ),
'contacts' => array(
'enable' => array(false, 'Enable contacts'),
'type' => array('mysql', ''),
'pdo_dsn' => array('mysql:host=127.0.0.1;port=3306;dbname=rainloop', ''),
'pdo_user' => array('root', ''),
'pdo_password' => array('', ''),
),
'security' => array( 'security' => array(
'csrf_protection' => array(true, 'csrf_protection' => array(true,
'Enable CSRF protection (http://en.wikipedia.org/wiki/Cross-site_request_forgery)'), 'Enable CSRF protection (http://en.wikipedia.org/wiki/Cross-site_request_forgery)'),

View file

@ -69,14 +69,15 @@ class PersonalAddressBook extends \RainLoop\Providers\AbstractProvider
* @param type $iLimit = 20 * @param type $iLimit = 20
* @param string $sSearch = '' * @param string $sSearch = ''
* @param bool $bAutoOnly = false * @param bool $bAutoOnly = false
* @param int $iResultCount = 0
* *
* @return array * @return array
*/ */
public function GetContacts($oAccount, public function GetContacts($oAccount,
$iOffset = 0, $iLimit = 20, $sSearch = '', $bAutoOnly = false) $iOffset = 0, $iLimit = 20, $sSearch = '', $bAutoOnly = false, &$iResultCount = 0)
{ {
return $this->IsActive() ? $this->oDriver->GetContacts($oAccount, return $this->IsActive() ? $this->oDriver->GetContacts($oAccount,
$iOffset, $iLimit, $sSearch, $bAutoOnly) : array(); $iOffset, $iLimit, $sSearch, $bAutoOnly, $iResultCount) : array();
} }
/** /**
@ -96,12 +97,13 @@ class PersonalAddressBook extends \RainLoop\Providers\AbstractProvider
/** /**
* @param \RainLoop\Account $oAccount * @param \RainLoop\Account $oAccount
* @param array $aEmails * @param array $aEmails
* @param bool $bCreateAuto = true
* *
* @return bool * @return bool
*/ */
public function IncFrec($oAccount, $aEmails) public function IncFrec($oAccount, $aEmails, $bCreateAuto = true)
{ {
return $this->IsActive() ? $this->oDriver->IncFrec($oAccount, $aEmails) : false; return $this->IsActive() ? $this->oDriver->IncFrec($oAccount, $aEmails, $bCreateAuto) : false;
} }
/** /**

View file

@ -29,6 +29,11 @@ class Contact
*/ */
public $Auto; public $Auto;
/**
* @var bool
*/
public $Shared;
/** /**
* @var int * @var int
*/ */
@ -39,6 +44,11 @@ class Contact
*/ */
public $Tags; public $Tags;
/**
* @var int
*/
public $IdPropertyFromSearch;
/** /**
* @var array * @var array
*/ */
@ -57,8 +67,10 @@ class Contact
$this->DisplayName = ''; $this->DisplayName = '';
$this->DisplayEmail = ''; $this->DisplayEmail = '';
$this->Auto = false; $this->Auto = false;
$this->Shared = false;
$this->Changed = \time(); $this->Changed = \time();
$this->Tags = array(); $this->Tags = array();
$this->IdPropertyFromSearch = 0;
$this->Properties = array(); $this->Properties = array();
} }

View file

@ -6,6 +6,11 @@ use RainLoop\Providers\PersonalAddressBook\Enumerations\PropertyType;
class Property class Property
{ {
/**
* @var int
*/
public $IdProperty;
/** /**
* @var int * @var int
*/ */
@ -38,6 +43,8 @@ class Property
public function Clear() public function Clear()
{ {
$this->IdProperty = 0;
$this->Type = PropertyType::UNKNOWN; $this->Type = PropertyType::UNKNOWN;
$this->TypeCustom = ''; $this->TypeCustom = '';

View file

@ -1,8 +1,10 @@
<?php <?php
namespace RainLoop\Providers\PersonalAddressBook;
use \RainLoop\Providers\PersonalAddressBook\Enumerations\PropertyType; use \RainLoop\Providers\PersonalAddressBook\Enumerations\PropertyType;
class MySqlPersonalAddressBookDriver class MySqlPersonalAddressBook
extends \RainLoop\Common\PdoAbstract extends \RainLoop\Common\PdoAbstract
implements \RainLoop\Providers\PersonalAddressBook\PersonalAddressBookInterface implements \RainLoop\Providers\PersonalAddressBook\PersonalAddressBookInterface
{ {
@ -26,14 +28,8 @@ class MySqlPersonalAddressBookDriver
$this->sDsn = $sDsn; $this->sDsn = $sDsn;
$this->sUser = $sUser; $this->sUser = $sUser;
$this->sPassword = $sPassword; $this->sPassword = $sPassword;
}
/** $this->bExplain = false;
* @return string
*/
public function Version()
{
return 'MySqlPersonalAddressBookDriver-v1';
} }
/** /**
@ -103,7 +99,7 @@ class MySqlPersonalAddressBookDriver
$aFreq = $this->getContactFreq($iUserID, $iIdContact); $aFreq = $this->getContactFreq($iUserID, $iIdContact);
$sSql = 'UPDATE `rainloop_pab_contacts` SET `display` = :display, `display_name` = :display_name, `display_email` = :display_email, '. $sSql = 'UPDATE `rainloop_pab_contacts` SET `display` = :display, `display_name` = :display_name, `display_email` = :display_email, '.
'`auto` = :auto, `changed` = :changed WHERE id_user = :id_user AND `id_contact` = :id_contact'; '`auto` = :auto, `shared` = :shared, `changed` = :changed WHERE id_user = :id_user AND `id_contact` = :id_contact';
$this->prepareAndExecute($sSql, $this->prepareAndExecute($sSql,
array( array(
@ -113,13 +109,14 @@ class MySqlPersonalAddressBookDriver
':display_name' => array($oContact->DisplayName, \PDO::PARAM_STR), ':display_name' => array($oContact->DisplayName, \PDO::PARAM_STR),
':display_email' => array($oContact->DisplayEmail, \PDO::PARAM_STR), ':display_email' => array($oContact->DisplayEmail, \PDO::PARAM_STR),
':auto' => array($oContact->Auto, \PDO::PARAM_INT), ':auto' => array($oContact->Auto, \PDO::PARAM_INT),
':shared' => array($oContact->Shared, \PDO::PARAM_INT),
':changed' => array($oContact->Changed, \PDO::PARAM_INT), ':changed' => array($oContact->Changed, \PDO::PARAM_INT),
) )
); );
// clear previos props // clear previos props
$this->prepareAndExecute( $this->prepareAndExecute(
'DELETE FROM `rainloop_pab_prop` WHERE `id_user` = :id_user AND `id_contact` = :id_contact', 'DELETE FROM `rainloop_pab_properties` WHERE `id_user` = :id_user AND `id_contact` = :id_contact',
array( array(
':id_user' => array($iUserID, \PDO::PARAM_INT), ':id_user' => array($iUserID, \PDO::PARAM_INT),
':id_contact' => array($iIdContact, \PDO::PARAM_INT) ':id_contact' => array($iIdContact, \PDO::PARAM_INT)
@ -129,8 +126,8 @@ class MySqlPersonalAddressBookDriver
else else
{ {
$sSql = 'INSERT INTO `rainloop_pab_contacts` '. $sSql = 'INSERT INTO `rainloop_pab_contacts` '.
'(`id_user`, `display`, `display_name`, `display_email`, `auto`, `changed`) VALUES '. '(`id_user`, `display`, `display_name`, `display_email`, `auto`, `shared`, `changed`) VALUES '.
'(:id_user, :display, :display_name, :display_email, :auto, :changed)'; '(:id_user, :display, :display_name, :display_email, :auto, :shared, :changed)';
$this->prepareAndExecute($sSql, $this->prepareAndExecute($sSql,
array( array(
@ -139,6 +136,7 @@ class MySqlPersonalAddressBookDriver
':display_name' => array($oContact->DisplayName, \PDO::PARAM_STR), ':display_name' => array($oContact->DisplayName, \PDO::PARAM_STR),
':display_email' => array($oContact->DisplayEmail, \PDO::PARAM_STR), ':display_email' => array($oContact->DisplayEmail, \PDO::PARAM_STR),
':auto' => array($oContact->Auto, \PDO::PARAM_INT), ':auto' => array($oContact->Auto, \PDO::PARAM_INT),
':shared' => array($oContact->Shared, \PDO::PARAM_INT),
':changed' => array($oContact->Changed, \PDO::PARAM_INT) ':changed' => array($oContact->Changed, \PDO::PARAM_INT)
) )
); );
@ -169,13 +167,15 @@ class MySqlPersonalAddressBookDriver
':type_custom' => array($oProp->TypeCustom, \PDO::PARAM_STR), ':type_custom' => array($oProp->TypeCustom, \PDO::PARAM_STR),
':value' => array($oProp->Value, \PDO::PARAM_STR), ':value' => array($oProp->Value, \PDO::PARAM_STR),
':value_custom' => array($oProp->ValueClear, \PDO::PARAM_STR), ':value_custom' => array($oProp->ValueClear, \PDO::PARAM_STR),
':auto' => array($oContact->Auto, \PDO::PARAM_INT),
':shared' => array($oContact->Shared, \PDO::PARAM_INT),
':frec' => array($iFreq, \PDO::PARAM_INT), ':frec' => array($iFreq, \PDO::PARAM_INT),
); );
} }
$sSql = 'INSERT INTO `rainloop_pab_prop` '. $sSql = 'INSERT INTO `rainloop_pab_properties` '.
'(`id_contact`, `id_user`, `type`, `type_custom`, `value`, `value_custom`, `frec`) VALUES '. '(`id_contact`, `id_user`, `type`, `type_custom`, `value`, `value_custom`, `auto`, `shared`, `frec`) VALUES '.
'(:id_contact, :id_user, :type, :type_custom, :value, :value_custom, :frec)'; '(:id_contact, :id_user, :type, :type_custom, :value, :value_custom, :auto, :shared, :frec)';
$this->prepareAndExecute($sSql, $aParams, true); $this->prepareAndExecute($sSql, $aParams, true);
} }
@ -211,9 +211,43 @@ class MySqlPersonalAddressBookDriver
return false; return false;
} }
return !!$this->prepareAndExecute( $sIDs = \implode(',', $aContactIds);
'DELETE FROM `rainloop_pab_contacts` WHERE `id_user` = :id_user AND `id_contact` IN ('.\implode(',', $aContactIds).')', $aParams = array(':id_user' => array($iUserID, \PDO::PARAM_INT));
array(':id_user' => array($iUserID, \PDO::PARAM_INT)));
$this->prepareAndExecute('DELETE FROM `rainloop_pab_tags_contacts` WHERE `id_contact` IN ('.$sIDs.')');
$this->prepareAndExecute('DELETE FROM `rainloop_pab_properties` WHERE `id_user` = :id_user AND `id_contact` IN ('.$sIDs.')', $aParams);
$this->prepareAndExecute('DELETE FROM `rainloop_pab_contacts` WHERE `id_user` = :id_user AND `id_contact` IN ('.$sIDs.')', $aParams);
return true;
}
/**
* @param \RainLoop\Account $oAccount
* @param array $aTagsIds
*
* @return bool
*/
public function DeleteTags($oAccount, $aTagsIds)
{
$iUserID = $this->getUserId($oAccount->ParentEmailHelper());
$aTagsIds = \array_filter($aTagsIds, function (&$mItem) {
$mItem = (int) \trim($mItem);
return 0 < $mItem;
});
if (0 === \count($aTagsIds))
{
return false;
}
$sIDs = \implode(',', $aTagsIds);
$aParams = array(':id_user' => array($iUserID, \PDO::PARAM_INT));
$this->prepareAndExecute('DELETE FROM `rainloop_pab_tags_contacts` WHERE `id_tag` IN ('.$sIDs.')');
$this->prepareAndExecute('DELETE FROM `rainloop_pab_tags` WHERE `id_user` = :id_user AND `id_tag` IN ('.$sIDs.')', $aParams);
return true;
} }
/** /**
@ -222,10 +256,11 @@ class MySqlPersonalAddressBookDriver
* @param int $iLimit = 20 * @param int $iLimit = 20
* @param string $sSearch = '' * @param string $sSearch = ''
* @param bool $bAutoOnly = false * @param bool $bAutoOnly = false
* @param int $iResultCount = 0
* *
* @return array * @return array
*/ */
public function GetContacts($oAccount, $iOffset = 0, $iLimit = 20, $sSearch = '', $bAutoOnly = false) public function GetContacts($oAccount, $iOffset = 0, $iLimit = 20, $sSearch = '', $bAutoOnly = false, &$iResultCount = 0)
{ {
$iOffset = 0 <= $iOffset ? $iOffset : 0; $iOffset = 0 <= $iOffset ? $iOffset : 0;
$iLimit = 0 < $iLimit ? (int) $iLimit : 20; $iLimit = 0 < $iLimit ? (int) $iLimit : 20;
@ -233,19 +268,71 @@ class MySqlPersonalAddressBookDriver
$iUserID = $this->getUserId($oAccount->ParentEmailHelper()); $iUserID = $this->getUserId($oAccount->ParentEmailHelper());
$iCount = 0;
$aSearchIds = array();
$aPropertyFromSearchIds = array();
if (0 < \strlen($sSearch))
{
$sSql = 'SELECT `id_prop`, `id_contact` FROM `rainloop_pab_properties` WHERE `id_user` = :id_user AND `auto` = :auto AND `value` LIKE :search ESCAPE \'=\' GROUP BY `id_contact`';
$aParams = array(
':id_user' => array($iUserID, \PDO::PARAM_INT),
':auto' => array($bAutoOnly ? 1 : 0, \PDO::PARAM_INT),
':search' => array($this->specialConvertSearchValue($sSearch, '='), \PDO::PARAM_STR)
);
$oStmt = $this->prepareAndExecute($sSql, $aParams);
if ($oStmt)
{
$aFetch = $oStmt->fetchAll(\PDO::FETCH_ASSOC);
if (\is_array($aFetch) && 0 < \count($aFetch))
{
foreach ($aFetch as $aItem)
{
$iIdContact = $aItem && isset($aItem['id_contact']) ? (int) $aItem['id_contact'] : 0;
if (0 < $iIdContact)
{
$aSearchIds[] = $iIdContact;
$aPropertyFromSearchIds[$iIdContact] = isset($aItem['id_prop']) ? (int) $aItem['id_prop'] : 0;
}
}
}
$iCount = \count($aSearchIds);
}
}
else
{
$sSql = 'SELECT COUNT(DISTINCT `id_contact`) as `contact_count` FROM `rainloop_pab_properties` WHERE `id_user` = :id_user AND `auto` = :auto';
$aParams = array(
':id_user' => array($iUserID, \PDO::PARAM_INT),
':auto' => array($bAutoOnly ? 1 : 0, \PDO::PARAM_INT)
);
$oStmt = $this->prepareAndExecute($sSql, $aParams);
if ($oStmt)
{
$aFetch = $oStmt->fetchAll(\PDO::FETCH_ASSOC);
if ($aFetch && isset($aFetch[0]['contact_count']) && is_numeric($aFetch[0]['contact_count']) && 0 < (int) $aFetch[0]['contact_count'])
{
$iCount = (int) $aFetch[0]['contact_count'];
}
}
}
$iResultCount = $iCount;
if (0 < $iCount)
{
$sSql = 'SELECT * FROM `rainloop_pab_contacts` WHERE id_user = :id_user AND `auto` = :auto'; $sSql = 'SELECT * FROM `rainloop_pab_contacts` WHERE id_user = :id_user AND `auto` = :auto';
$aParams = array( $aParams = array(
':id_user' => array($iUserID, \PDO::PARAM_INT), ':id_user' => array($iUserID, \PDO::PARAM_INT),
':auto' => array($bAutoOnly ? 1 : 0, \PDO::PARAM_INT) ':auto' => array($bAutoOnly ? 1 : 0, \PDO::PARAM_INT)
); );
if (0 < \strlen($sSearch)) if (0 < \count($aSearchIds))
{ {
$sSql .= ' AND `id_contact` IN ('. $sSql .= ' AND `id_contact` IN ('.implode(',', $aSearchIds).')';
'SELECT DISTINCT `id_contact` FROM `rainloop_pab_prop` WHERE id_user = :id_user AND `value` LIKE :search ESCAPE \'=\''.
')';
$aParams[':search'] = array($this->specialConvertSearchValue($sSearch, '='), \PDO::PARAM_STR);
} }
$sSql .= ' ORDER BY `display` ASC LIMIT :limit OFFSET :offset'; $sSql .= ' ORDER BY `display` ASC LIMIT :limit OFFSET :offset';
@ -275,6 +362,8 @@ class MySqlPersonalAddressBookDriver
$oContact->DisplayEmail = isset($aItem['display_email']) ? (string) $aItem['display_email'] : ''; $oContact->DisplayEmail = isset($aItem['display_email']) ? (string) $aItem['display_email'] : '';
$oContact->Auto = isset($aItem['auto']) ? (bool) $aItem['auto'] : false; $oContact->Auto = isset($aItem['auto']) ? (bool) $aItem['auto'] : false;
$oContact->Changed = isset($aItem['changed']) ? (int) $aItem['changed'] : 0; $oContact->Changed = isset($aItem['changed']) ? (int) $aItem['changed'] : 0;
$oContact->IdPropertyFromSearch = isset($aPropertyFromSearchIds[$iIdContact]) &&
0 < $aPropertyFromSearchIds[$iIdContact] ? $aPropertyFromSearchIds[$iIdContact] : 0;
$aContacts[$iIdContact] = $oContact; $aContacts[$iIdContact] = $oContact;
} }
@ -287,7 +376,7 @@ class MySqlPersonalAddressBookDriver
{ {
$oStmt->closeCursor(); $oStmt->closeCursor();
$sSql = 'SELECT * FROM `rainloop_pab_prop` WHERE id_user = :id_user AND `id_contact` IN ('.\implode(',', $aIdContacts).')'; $sSql = 'SELECT * FROM `rainloop_pab_properties` WHERE id_user = :id_user AND `id_contact` IN ('.\implode(',', $aIdContacts).')';
$oStmt = $this->prepareAndExecute($sSql, array( $oStmt = $this->prepareAndExecute($sSql, array(
':id_user' => array($iUserID, \PDO::PARAM_INT) ':id_user' => array($iUserID, \PDO::PARAM_INT)
)); ));
@ -305,6 +394,7 @@ class MySqlPersonalAddressBookDriver
if (0 < $iId && isset($aContacts[$iId])) if (0 < $iId && isset($aContacts[$iId]))
{ {
$oProperty = new \RainLoop\Providers\PersonalAddressBook\Classes\Property(); $oProperty = new \RainLoop\Providers\PersonalAddressBook\Classes\Property();
$oProperty->IdProperty = (int) $aItem['id_prop'];
$oProperty->Type = (int) $aItem['type']; $oProperty->Type = (int) $aItem['type'];
$oProperty->TypeCustom = isset($aItem['type_custom']) ? (string) $aItem['type_custom'] : ''; $oProperty->TypeCustom = isset($aItem['type_custom']) ? (string) $aItem['type_custom'] : '';
$oProperty->Value = (string) $aItem['value']; $oProperty->Value = (string) $aItem['value'];
@ -328,6 +418,7 @@ class MySqlPersonalAddressBookDriver
} }
} }
} }
}
return array(); return array();
} }
@ -355,7 +446,7 @@ class MySqlPersonalAddressBookDriver
PropertyType::EMAIl_PERSONAL, PropertyType::EMAIl_BUSSINES, PropertyType::EMAIl_OTHER, PropertyType::FULLNAME PropertyType::EMAIl_PERSONAL, PropertyType::EMAIl_BUSSINES, PropertyType::EMAIl_OTHER, PropertyType::FULLNAME
)); ));
$sSql = 'SELECT `id_contact`, `id_prop`, `type`, `value` FROM `rainloop_pab_prop` '. $sSql = 'SELECT `id_contact`, `id_prop`, `type`, `value` FROM `rainloop_pab_properties` '.
'WHERE id_user = :id_user AND `type` IN ('.$sTypes.') AND `value` LIKE :search ESCAPE \'=\''; 'WHERE id_user = :id_user AND `type` IN ('.$sTypes.') AND `value` LIKE :search ESCAPE \'=\'';
$aParams = array( $aParams = array(
@ -364,7 +455,8 @@ class MySqlPersonalAddressBookDriver
':search' => array($this->specialConvertSearchValue($sSearch, '='), \PDO::PARAM_STR) ':search' => array($this->specialConvertSearchValue($sSearch, '='), \PDO::PARAM_STR)
); );
$sSql .= ' ORDER BY `frec` DESC LIMIT :limit'; $sSql .= ' ORDER BY `frec` DESC';
$sSql .= ' LIMIT :limit';
$aResult = array(); $aResult = array();
$aFirstResult = array(); $aFirstResult = array();
@ -417,13 +509,12 @@ class MySqlPersonalAddressBookDriver
PropertyType::EMAIl_PERSONAL, PropertyType::EMAIl_BUSSINES, PropertyType::EMAIl_OTHER, PropertyType::FULLNAME PropertyType::EMAIl_PERSONAL, PropertyType::EMAIl_BUSSINES, PropertyType::EMAIl_OTHER, PropertyType::FULLNAME
)); ));
$sSql = 'SELECT `id_prop`, `id_contact`, `type`, `value` FROM `rainloop_pab_prop` '. $sSql = 'SELECT `id_prop`, `id_contact`, `type`, `value` FROM `rainloop_pab_properties` '.
'WHERE id_user = :id_user AND `type` IN ('.$sTypes.') AND `id_contact` IN ('.\implode(',', $aIdContacts).')'; 'WHERE id_user = :id_user AND `type` IN ('.$sTypes.') AND `id_contact` IN ('.\implode(',', $aIdContacts).')';
$oStmt = $this->prepareAndExecute($sSql, array( $oStmt = $this->prepareAndExecute($sSql, array(
':id_user' => array($iUserID, \PDO::PARAM_INT) ':id_user' => array($iUserID, \PDO::PARAM_INT)
)); ));
if ($oStmt) if ($oStmt)
{ {
$aFetch = $oStmt->fetchAll(\PDO::FETCH_ASSOC); $aFetch = $oStmt->fetchAll(\PDO::FETCH_ASSOC);
@ -504,10 +595,11 @@ class MySqlPersonalAddressBookDriver
/** /**
* @param \RainLoop\Account $oAccount * @param \RainLoop\Account $oAccount
* @param array $aEmails * @param array $aEmails
* @param bool $bCreateAuto = true
* *
* @return bool * @return bool
*/ */
public function IncFrec($oAccount, $aEmails) public function IncFrec($oAccount, $aEmails, $bCreateAuto = true)
{ {
$iUserID = $this->getUserId($oAccount->ParentEmailHelper()); $iUserID = $this->getUserId($oAccount->ParentEmailHelper());
@ -531,12 +623,17 @@ class MySqlPersonalAddressBookDriver
PropertyType::EMAIl_PERSONAL, PropertyType::EMAIl_BUSSINES, PropertyType::EMAIl_OTHER PropertyType::EMAIl_PERSONAL, PropertyType::EMAIl_BUSSINES, PropertyType::EMAIl_OTHER
)); ));
$sSql = 'SELECT `value` FROM `rainloop_pab_prop` WHERE id_user = :id_user AND `type` IN ('.$sTypes.')'; $aExists = array();
$aEmailsToCreate = array();
$aEmailsToUpdate = array();
if ($bCreateAuto)
{
$sSql = 'SELECT `value` FROM `rainloop_pab_properties` WHERE id_user = :id_user AND `type` IN ('.$sTypes.')';
$oStmt = $this->prepareAndExecute($sSql, array( $oStmt = $this->prepareAndExecute($sSql, array(
':id_user' => array($iUserID, \PDO::PARAM_INT) ':id_user' => array($iUserID, \PDO::PARAM_INT)
)); ));
$aExists = array();
if ($oStmt) if ($oStmt)
{ {
$aFetch = $oStmt->fetchAll(\PDO::FETCH_ASSOC); $aFetch = $oStmt->fetchAll(\PDO::FETCH_ASSOC);
@ -552,7 +649,6 @@ class MySqlPersonalAddressBookDriver
} }
} }
$aEmailsToUpdate = array();
$aEmailsToCreate = \array_filter($aEmailsObjects, function ($oItem) use ($aExists, &$aEmailsToUpdate) { $aEmailsToCreate = \array_filter($aEmailsObjects, function ($oItem) use ($aExists, &$aEmailsToUpdate) {
if ($oItem) if ($oItem)
{ {
@ -566,6 +662,21 @@ class MySqlPersonalAddressBookDriver
return false; return false;
}); });
}
else
{
foreach ($aEmailsObjects as $oItem)
{
if ($oItem)
{
$sEmail = \strtolower(\trim($oItem->GetEmail()));
if (0 < \strlen($sEmail))
{
$aEmailsToUpdate[] = $sEmail;
}
}
}
}
unset($aEmails, $aEmailsObjects); unset($aEmails, $aEmailsObjects);
@ -603,7 +714,7 @@ class MySqlPersonalAddressBookDriver
} }
} }
$sSql = 'UPDATE `rainloop_pab_prop` SET `frec` = `frec` + 1 WHERE id_user = :id_user AND `type` IN ('.$sTypes; $sSql = 'UPDATE `rainloop_pab_properties` SET `frec` = `frec` + 1 WHERE id_user = :id_user AND `type` IN ('.$sTypes;
$aEmailsQuoted = \array_map(function ($mItem) use ($self) { $aEmailsQuoted = \array_map(function ($mItem) use ($self) {
return $self->quoteValue($mItem); return $self->quoteValue($mItem);
@ -623,6 +734,14 @@ class MySqlPersonalAddressBookDriver
)); ));
} }
/**
* @return string
*/
public function Version()
{
return 'MySqlPersonalAddressBookDriver-v14';
}
/** /**
* @return bool * @return bool
*/ */
@ -640,16 +759,16 @@ class MySqlPersonalAddressBookDriver
`display_name` varchar(255) NOT NULL DEFAULT \'\', `display_name` varchar(255) NOT NULL DEFAULT \'\',
`display_email` varchar(255) NOT NULL DEFAULT \'\', `display_email` varchar(255) NOT NULL DEFAULT \'\',
`auto` int(1) UNSIGNED NOT NULL DEFAULT \'0\', `auto` int(1) UNSIGNED NOT NULL DEFAULT \'0\',
`shared` int(1) UNSIGNED NOT NULL DEFAULT \'0\',
`changed` int(11) UNSIGNED NOT NULL DEFAULT \'0\', `changed` int(11) UNSIGNED NOT NULL DEFAULT \'0\',
PRIMARY KEY(`id_contact`), PRIMARY KEY(`id_contact`),
CONSTRAINT `id_user_fk_rainloop_pab_contacts` FOREIGN KEY (`id_user`) INDEX `id_user_index` (`id_user`)
REFERENCES `rainloop_users` (`id_user`) ON DELETE CASCADE ON UPDATE CASCADE
) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */;', ) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */;',
// -- rainloop_pab_prop -- // -- rainloop_pab_properties --
'CREATE TABLE IF NOT EXISTS `rainloop_pab_prop` ( 'CREATE TABLE IF NOT EXISTS `rainloop_pab_properties` (
`id_prop` int(11) UNSIGNED NOT NULL AUTO_INCREMENT, `id_prop` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`id_contact` int(11) UNSIGNED NOT NULL, `id_contact` int(11) UNSIGNED NOT NULL,
@ -658,13 +777,13 @@ class MySqlPersonalAddressBookDriver
`type_custom` varchar(50) /*!40101 CHARACTER SET ascii COLLATE ascii_general_ci */ NOT NULL DEFAULT \'\', `type_custom` varchar(50) /*!40101 CHARACTER SET ascii COLLATE ascii_general_ci */ NOT NULL DEFAULT \'\',
`value` varchar(255) NOT NULL DEFAULT \'\', `value` varchar(255) NOT NULL DEFAULT \'\',
`value_custom` varchar(255) NOT NULL DEFAULT \'\', `value_custom` varchar(255) NOT NULL DEFAULT \'\',
`auto` int(1) UNSIGNED NOT NULL DEFAULT \'0\',
`shared` int(1) UNSIGNED NOT NULL DEFAULT \'0\',
`frec` int(11) UNSIGNED NOT NULL DEFAULT \'0\', `frec` int(11) UNSIGNED NOT NULL DEFAULT \'0\',
PRIMARY KEY(`id_prop`), PRIMARY KEY(`id_prop`),
INDEX `id_user_id_contact_index` (`id_user`, `id_contact`), INDEX `id_user_index` (`id_user`),
INDEX `id_user_value_index` (`id_user`, `value`), INDEX `id_user_id_contact_index` (`id_user`, `id_contact`)
CONSTRAINT `id_contact_fk_rainloop_pab_prop` FOREIGN KEY (`id_contact`)
REFERENCES `rainloop_pab_contacts` (`id_contact`) ON DELETE CASCADE ON UPDATE CASCADE
) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */;', ) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */;',
@ -676,9 +795,7 @@ class MySqlPersonalAddressBookDriver
`name` varchar(255) NOT NULL, `name` varchar(255) NOT NULL,
PRIMARY KEY(`id_tag`), PRIMARY KEY(`id_tag`),
UNIQUE `id_user_name_unique` (`id_user`, `name`), INDEX `id_user_index` (`id_user`)
CONSTRAINT `id_user_fk_rainloop_pab_tags` FOREIGN KEY (`id_user`)
REFERENCES `rainloop_users` (`id_user`) ON DELETE CASCADE ON UPDATE CASCADE
) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */;', ) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */;',
@ -688,10 +805,7 @@ class MySqlPersonalAddressBookDriver
`id_tag` int(11) UNSIGNED NOT NULL, `id_tag` int(11) UNSIGNED NOT NULL,
`id_contact` int(11) UNSIGNED NOT NULL, `id_contact` int(11) UNSIGNED NOT NULL,
CONSTRAINT `id_contact_fk_rainloop_tags_contacts` FOREIGN KEY (`id_contact`) INDEX `id_contact_id_tag_index` (`id_contact`, `id_tag`)
REFERENCES `rainloop_pab_contacts` (`id_contact`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `id_tag_fk_rainloop_tags_contacts` FOREIGN KEY (`id_tag`)
REFERENCES `rainloop_pab_tags` (`id_tag`) ON DELETE CASCADE ON UPDATE CASCADE
) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */;' ) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */;'
))); )));
@ -710,7 +824,7 @@ class MySqlPersonalAddressBookDriver
PropertyType::EMAIl_PERSONAL, PropertyType::EMAIl_BUSSINES, PropertyType::EMAIl_OTHER PropertyType::EMAIl_PERSONAL, PropertyType::EMAIl_BUSSINES, PropertyType::EMAIl_OTHER
)); ));
$sSql = 'SELECT `value`, `frec` FROM `rainloop_pab_prop` WHERE id_user = :id_user AND `id_contact` = :id_contact AND `type` IN ('.$sTypes.')'; $sSql = 'SELECT `value`, `frec` FROM `rainloop_pab_properties` WHERE id_user = :id_user AND `id_contact` = :id_contact AND `type` IN ('.$sTypes.')';
$aParams = array( $aParams = array(
':id_user' => array($iUserID, \PDO::PARAM_INT), ':id_user' => array($iUserID, \PDO::PARAM_INT),
':id_contact' => array($iIdContact, \PDO::PARAM_INT) ':id_contact' => array($iIdContact, \PDO::PARAM_INT)

View file

@ -30,17 +30,26 @@ interface PersonalAddressBookInterface
*/ */
public function DeleteContacts($oAccount, $aContactIds); public function DeleteContacts($oAccount, $aContactIds);
/**
* @param \RainLoop\Account $oAccount
* @param array $aTagsIds
*
* @return bool
*/
public function DeleteTags($oAccount, $aTagsIds);
/** /**
* @param \RainLoop\Account $oAccount * @param \RainLoop\Account $oAccount
* @param int $iOffset = 0 * @param int $iOffset = 0
* @param type $iLimit = 20 * @param type $iLimit = 20
* @param string $sSearch = '' * @param string $sSearch = ''
* @param bool $bAutoOnly = false * @param bool $bAutoOnly = false
* @param int $iResultCount = 0
* *
* @return array * @return array
*/ */
public function GetContacts($oAccount, public function GetContacts($oAccount,
$iOffset = 0, $iLimit = 20, $sSearch = '', $bAutoOnly = false); $iOffset = 0, $iLimit = 20, $sSearch = '', $bAutoOnly = false, &$iResultCount = 0);
/** /**
* @param \RainLoop\Account $oAccount * @param \RainLoop\Account $oAccount

View file

@ -151,11 +151,7 @@
<span data-bind="text: userUsageProc"></span>% <span data-bind="text: userUsageProc"></span>%
</span> </span>
<div class="pull-right"> <div class="pull-right">
<div class="pagenator g-ui-user-select-none" data-bind="foreach: messageListPagenator"> <!-- ko template: { name: 'Pagenator', data: messageListPagenator } --><!-- /ko -->
<a class="page" data-bind="css: { 'current': current, 'custom': custom }, title: title">
<span class="pageNumber" data-bind="text: name"></span>
</a>
</div>
</div> </div>
</div> </div>
</div> </div>

View file

@ -0,0 +1,5 @@
<div class="e-pagenator g-ui-user-select-none" data-bind="foreach: $data">
<a class="e-page" data-bind="css: { 'current': current, 'custom': custom }, title: title">
<span class="e-page-number" data-bind="text: name"></span>
</a>
</div>

View file

@ -54,6 +54,11 @@
</div> </div>
</div> </div>
</div> </div>
<div class="b-list-footer-toopbar">
<div class="pull-right footer-pager">
<!-- ko template: { name: 'Pagenator', data: contactsPagenator } --><!-- /ko -->
</div>
</div>
<div class="b-view-content" data-bind="nano: true"> <div class="b-view-content" data-bind="nano: true">
<div class="content g-scrollbox"> <div class="content g-scrollbox">
<div class="content-wrapper"> <div class="content-wrapper">

View file

@ -129,8 +129,8 @@ SEARCHING_DESC = "Searching..."
LEGEND_CONTACTS = "Contacts" LEGEND_CONTACTS = "Contacts"
SEARCH_INPUT_PLACEHOLDER = "Search" SEARCH_INPUT_PLACEHOLDER = "Search"
BUTTON_ADD_CONTACT = "Add Contact" BUTTON_ADD_CONTACT = "Add Contact"
BUTTON_CREATE_CONTACT = "Create Contact" BUTTON_CREATE_CONTACT = "Create"
BUTTON_UPDATE_CONTACT = "Update Contact" BUTTON_UPDATE_CONTACT = "Update"
LIST_LOADING = "Loading" LIST_LOADING = "Loading"
EMPTY_LIST = "No contacts here" EMPTY_LIST = "No contacts here"
EMPTY_SEARCH = "No contacts found" EMPTY_SEARCH = "No contacts found"

View file

@ -129,8 +129,8 @@ SEARCHING_DESC = "Buscando..."
LEGEND_CONTACTS = "Contactos" LEGEND_CONTACTS = "Contactos"
SEARCH_INPUT_PLACEHOLDER = "Buscar" SEARCH_INPUT_PLACEHOLDER = "Buscar"
BUTTON_ADD_CONTACT = "Añadir Contacto" BUTTON_ADD_CONTACT = "Añadir Contacto"
BUTTON_CREATE_CONTACT = "Crear Contacto" BUTTON_CREATE_CONTACT = "Crear"
BUTTON_UPDATE_CONTACT = "Actualizar Contacto" BUTTON_UPDATE_CONTACT = "Actualizar"
LIST_LOADING = "Cargando" LIST_LOADING = "Cargando"
EMPTY_LIST = "No hay contactos aquí" EMPTY_LIST = "No hay contactos aquí"
EMPTY_SEARCH = "No se encontraron contactos" EMPTY_SEARCH = "No se encontraron contactos"

View file

@ -129,8 +129,8 @@ SEARCHING_DESC = "Recherche..."
LEGEND_CONTACTS = "Contacts" LEGEND_CONTACTS = "Contacts"
SEARCH_INPUT_PLACEHOLDER = "Recherche" SEARCH_INPUT_PLACEHOLDER = "Recherche"
BUTTON_ADD_CONTACT = "Ajouter un contact" BUTTON_ADD_CONTACT = "Ajouter un contact"
BUTTON_CREATE_CONTACT = "Créer un contact" BUTTON_CREATE_CONTACT = "Créer"
BUTTON_UPDATE_CONTACT = "Modifier un contact" BUTTON_UPDATE_CONTACT = "Modifier"
LIST_LOADING = "Chargement" LIST_LOADING = "Chargement"
EMPTY_LIST = "Aucun contact" EMPTY_LIST = "Aucun contact"
EMPTY_SEARCH = "Aucun contact trouvé" EMPTY_SEARCH = "Aucun contact trouvé"

View file

@ -129,8 +129,8 @@ SEARCHING_DESC = "Leita..."
LEGEND_CONTACTS = "Tengiliðir" LEGEND_CONTACTS = "Tengiliðir"
SEARCH_INPUT_PLACEHOLDER = "Leita" SEARCH_INPUT_PLACEHOLDER = "Leita"
BUTTON_ADD_CONTACT = "Bæta við tengilið" BUTTON_ADD_CONTACT = "Bæta við tengilið"
BUTTON_CREATE_CONTACT = "Búa til tengilið" BUTTON_CREATE_CONTACT = "Búa til"
BUTTON_UPDATE_CONTACT = "Uppfæra tengilið" BUTTON_UPDATE_CONTACT = "Uppfæra"
LIST_LOADING = "Hleð" LIST_LOADING = "Hleð"
EMPTY_LIST = "Engir tengiliðir hér" EMPTY_LIST = "Engir tengiliðir hér"
EMPTY_SEARCH = "Engir tengiliðir fundust" EMPTY_SEARCH = "Engir tengiliðir fundust"

View file

@ -129,8 +129,8 @@ SEARCHING_DESC = "Meklē..."
LEGEND_CONTACTS = "Kontakti" LEGEND_CONTACTS = "Kontakti"
SEARCH_INPUT_PLACEHOLDER = "Meklēt" SEARCH_INPUT_PLACEHOLDER = "Meklēt"
BUTTON_ADD_CONTACT = "Pievienot kontaktu" BUTTON_ADD_CONTACT = "Pievienot kontaktu"
BUTTON_CREATE_CONTACT = "Izveidot kontaktu" BUTTON_CREATE_CONTACT = "Izveidot"
BUTTON_UPDATE_CONTACT = "Atjaunot kontaktu" BUTTON_UPDATE_CONTACT = "Atjaunot"
LIST_LOADING = "Lādējās" LIST_LOADING = "Lādējās"
EMPTY_LIST = "Nav kontaktu" EMPTY_LIST = "Nav kontaktu"
EMPTY_SEARCH = "Kontakti nav atrasti" EMPTY_SEARCH = "Kontakti nav atrasti"

View file

@ -129,8 +129,8 @@ SEARCHING_DESC = "Zoeken..."
LEGEND_CONTACTS = "Contacten" LEGEND_CONTACTS = "Contacten"
SEARCH_INPUT_PLACEHOLDER = "Zoeken" SEARCH_INPUT_PLACEHOLDER = "Zoeken"
BUTTON_ADD_CONTACT = "Contact Toevoegen" BUTTON_ADD_CONTACT = "Contact Toevoegen"
BUTTON_CREATE_CONTACT = "Nieuw Contact" BUTTON_CREATE_CONTACT = "Nieuw"
BUTTON_UPDATE_CONTACT = "Update Contact" BUTTON_UPDATE_CONTACT = "Update"
LIST_LOADING = "Laden" LIST_LOADING = "Laden"
EMPTY_LIST = "Geen contacten hier" EMPTY_LIST = "Geen contacten hier"
EMPTY_SEARCH = "Geen contacten gevonden" EMPTY_SEARCH = "Geen contacten gevonden"

View file

@ -129,8 +129,8 @@ SEARCHING_DESC = "Wyszukiwanie..."
LEGEND_CONTACTS = "Kontakty" LEGEND_CONTACTS = "Kontakty"
SEARCH_INPUT_PLACEHOLDER = "Szukaj" SEARCH_INPUT_PLACEHOLDER = "Szukaj"
BUTTON_ADD_CONTACT = "Dodaj Kontakt" BUTTON_ADD_CONTACT = "Dodaj Kontakt"
BUTTON_CREATE_CONTACT = "Utwórz Kontakt" BUTTON_CREATE_CONTACT = "Utwórz"
BUTTON_UPDATE_CONTACT = "Aktualizuj Kontakt" BUTTON_UPDATE_CONTACT = "Aktualizuj"
LIST_LOADING = "Ładowanie" LIST_LOADING = "Ładowanie"
EMPTY_LIST = "Brak kontaktów" EMPTY_LIST = "Brak kontaktów"
EMPTY_SEARCH = "Nie znaleziono żadnych kontaktów" EMPTY_SEARCH = "Nie znaleziono żadnych kontaktów"

View file

@ -129,8 +129,8 @@ SEARCHING_DESC = "Procurando..."
LEGEND_CONTACTS = "Contatos" LEGEND_CONTACTS = "Contatos"
SEARCH_INPUT_PLACEHOLDER = "Procurar" SEARCH_INPUT_PLACEHOLDER = "Procurar"
BUTTON_ADD_CONTACT = "Adicionar Contatos" BUTTON_ADD_CONTACT = "Adicionar Contatos"
BUTTON_CREATE_CONTACT = "Criar Contatos" BUTTON_CREATE_CONTACT = "Criar"
BUTTON_UPDATE_CONTACT = "Atualizar Contatos" BUTTON_UPDATE_CONTACT = "Atualizar"
LIST_LOADING = "Carregando" LIST_LOADING = "Carregando"
EMPTY_LIST = "Nenhum contato aqui" EMPTY_LIST = "Nenhum contato aqui"
EMPTY_SEARCH = "Nenhum contato encontrado" EMPTY_SEARCH = "Nenhum contato encontrado"

View file

@ -129,8 +129,8 @@ SEARCHING_DESC = "Procurando..."
LEGEND_CONTACTS = "Contatos" LEGEND_CONTACTS = "Contatos"
SEARCH_INPUT_PLACEHOLDER = "Procurar" SEARCH_INPUT_PLACEHOLDER = "Procurar"
BUTTON_ADD_CONTACT = "Adicionar Contatos" BUTTON_ADD_CONTACT = "Adicionar Contatos"
BUTTON_CREATE_CONTACT = "Criar Contatos" BUTTON_CREATE_CONTACT = "Criar"
BUTTON_UPDATE_CONTACT = "Atualizar Contatos" BUTTON_UPDATE_CONTACT = "Atualizar"
LIST_LOADING = "Carregando" LIST_LOADING = "Carregando"
EMPTY_LIST = "Nenhum contato aqui" EMPTY_LIST = "Nenhum contato aqui"
EMPTY_SEARCH = "Nenhum contato encontrado" EMPTY_SEARCH = "Nenhum contato encontrado"

View file

@ -129,8 +129,8 @@ SEARCHING_DESC = "Поиск..."
LEGEND_CONTACTS = "Контакты" LEGEND_CONTACTS = "Контакты"
SEARCH_INPUT_PLACEHOLDER = "Поиск контактов" SEARCH_INPUT_PLACEHOLDER = "Поиск контактов"
BUTTON_ADD_CONTACT = "Добавить контакт" BUTTON_ADD_CONTACT = "Добавить контакт"
BUTTON_CREATE_CONTACT = "Сохранить контакт" BUTTON_CREATE_CONTACT = "Сохранить"
BUTTON_UPDATE_CONTACT = "Обновить контакт" BUTTON_UPDATE_CONTACT = "Обновить"
LIST_LOADING = "Загрузка" LIST_LOADING = "Загрузка"
EMPTY_LIST = "Нет контактов" EMPTY_LIST = "Нет контактов"
EMPTY_SEARCH = "Контакты не найдены" EMPTY_SEARCH = "Контакты не найдены"

View file

@ -5736,10 +5736,29 @@ html.no-rgba .modal {
vertical-align: top; vertical-align: top;
text-align: left; text-align: left;
} }
.g-ui-height-100proc {
height: 100%;
}
.g-ui-resizable-delimiter-highlight { .g-ui-resizable-delimiter-highlight {
border: none; border: none;
border-right: 6px solid #aaa; border-right: 6px solid #aaa;
} }
.e-pagenator .e-page {
display: inline-block;
color: #999;
text-decoration: none;
font-size: 24px;
padding: 3px;
cursor: pointer;
}
.e-pagenator .e-page:hover .e-page-number {
color: #555;
}
.e-pagenator .e-page.current .e-page-number {
font-size: 28px;
color: #333;
border-bottom: 2px solid #000;
}
html.rgba .g-ui-resizable-delimiter-highlight { html.rgba .g-ui-resizable-delimiter-highlight {
border-right-color: rgba(0, 0, 0, 0.2); border-right-color: rgba(0, 0, 0, 0.2);
} }
@ -6707,22 +6726,6 @@ html.rl-no-preview-pane .messageList.message-selected {
.messageList.hideMessageListCheckbox .sidebarParent { .messageList.hideMessageListCheckbox .sidebarParent {
margin-right: 10px !important; margin-right: 10px !important;
} }
.messageList .pagenator .page {
display: inline-block;
color: #999;
text-decoration: none;
font-size: 24px;
padding: 3px;
cursor: pointer;
}
.messageList .pagenator .page:hover .pageNumber {
color: #555;
}
.messageList .pagenator .page.current .pageNumber {
font-size: 28px;
color: #333;
border-bottom: 2px solid #000;
}
.draggablePlace { .draggablePlace {
z-index: 10002; z-index: 10002;
color: #fff; color: #fff;
@ -6966,6 +6969,12 @@ html.rl-no-preview-pane .messageView.message-selected {
color: #000; color: #000;
font-family: arial, sans-serif; font-family: arial, sans-serif;
} }
.messageView .b-content .messageItem .bodyText .b-text-part div[data-x-div-type=html] {
height: 100%;
}
.messageView .b-content .messageItem .bodyText .b-text-part div[data-x-div-type=html] div[data-x-div-type=html] {
height: 100%;
}
.messageView .b-content .messageItem .bodyText .b-text-part a { .messageView .b-content .messageItem .bodyText .b-text-part a {
color: blue; color: blue;
text-decoration: underline; text-decoration: underline;
@ -7108,20 +7117,35 @@ html.rl-message-fullscreen .messageView .b-content .buttonFull {
padding: 0; padding: 0;
height: 45px; height: 45px;
text-align: center; text-align: center;
width: 250px; width: 270px;
-webkit-box-shadow: inset 0 -1px 0 #cccccc; -webkit-box-shadow: inset 0 -1px 0 #cccccc;
-moz-box-shadow: inset 0 -1px 0 #cccccc; -moz-box-shadow: inset 0 -1px 0 #cccccc;
box-shadow: inset 0 -1px 0 #cccccc; box-shadow: inset 0 -1px 0 #cccccc;
} }
.b-contacts-content.modal .b-list-toopbar .e-search { .b-contacts-content.modal .b-list-toopbar .e-search {
margin-top: 7px; margin-top: 7px;
width: 245px;
}
.b-contacts-content.modal .b-list-footer-toopbar {
position: absolute;
left: 0;
bottom: 0;
height: 105px;
width: 270px;
background-color: #eee;
-webkit-box-shadow: inset 0 1px 0 #cccccc;
-moz-box-shadow: inset 0 1px 0 #cccccc;
box-shadow: inset 0 1px 0 #cccccc;
}
.b-contacts-content.modal .b-list-footer-toopbar .footer-pager {
padding: 8px 10px 0 0;
} }
.b-contacts-content.modal .b-list-content { .b-contacts-content.modal .b-list-content {
position: absolute; position: absolute;
top: 45px; top: 45px;
bottom: 60px; bottom: 105px;
left: 0; left: 0;
width: 250px; width: 270px;
overflow: hidden; overflow: hidden;
overflow-y: auto; overflow-y: auto;
} }
@ -7135,6 +7159,9 @@ html.rl-message-fullscreen .messageView .b-content .buttonFull {
font-size: 14px; font-size: 14px;
line-height: 13px; line-height: 13px;
background-color: #fff; background-color: #fff;
-webkit-box-shadow: inset 0 -1px 0 #cccccc;
-moz-box-shadow: inset 0 -1px 0 #cccccc;
box-shadow: inset 0 -1px 0 #cccccc;
} }
.b-contacts-content.modal .b-list-content .listEmptyList, .b-contacts-content.modal .b-list-content .listEmptyList,
.b-contacts-content.modal .b-list-content .listEmptyListLoading, .b-contacts-content.modal .b-list-content .listEmptyListLoading,
@ -7232,7 +7259,7 @@ html.rl-message-fullscreen .messageView .b-content .buttonFull {
position: absolute; position: absolute;
top: 0; top: 0;
bottom: 60px; bottom: 60px;
left: 250px; left: 270px;
right: 0; right: 0;
overflow: hidden; overflow: hidden;
overflow-y: auto; overflow-y: auto;

File diff suppressed because one or more lines are too long

View file

@ -3581,10 +3581,29 @@ html.no-rgba .modal {
vertical-align: top; vertical-align: top;
text-align: left; text-align: left;
} }
.g-ui-height-100proc {
height: 100%;
}
.g-ui-resizable-delimiter-highlight { .g-ui-resizable-delimiter-highlight {
border: none; border: none;
border-right: 6px solid #aaa; border-right: 6px solid #aaa;
} }
.e-pagenator .e-page {
display: inline-block;
color: #999;
text-decoration: none;
font-size: 24px;
padding: 3px;
cursor: pointer;
}
.e-pagenator .e-page:hover .e-page-number {
color: #555;
}
.e-pagenator .e-page.current .e-page-number {
font-size: 28px;
color: #333;
border-bottom: 2px solid #000;
}
html.rgba .g-ui-resizable-delimiter-highlight { html.rgba .g-ui-resizable-delimiter-highlight {
border-right-color: rgba(0, 0, 0, 0.2); border-right-color: rgba(0, 0, 0, 0.2);
} }
@ -4552,22 +4571,6 @@ html.rl-no-preview-pane .messageList.message-selected {
.messageList.hideMessageListCheckbox .sidebarParent { .messageList.hideMessageListCheckbox .sidebarParent {
margin-right: 10px !important; margin-right: 10px !important;
} }
.messageList .pagenator .page {
display: inline-block;
color: #999;
text-decoration: none;
font-size: 24px;
padding: 3px;
cursor: pointer;
}
.messageList .pagenator .page:hover .pageNumber {
color: #555;
}
.messageList .pagenator .page.current .pageNumber {
font-size: 28px;
color: #333;
border-bottom: 2px solid #000;
}
.draggablePlace { .draggablePlace {
z-index: 10002; z-index: 10002;
color: #fff; color: #fff;
@ -4811,6 +4814,12 @@ html.rl-no-preview-pane .messageView.message-selected {
color: #000; color: #000;
font-family: arial, sans-serif; font-family: arial, sans-serif;
} }
.messageView .b-content .messageItem .bodyText .b-text-part div[data-x-div-type=html] {
height: 100%;
}
.messageView .b-content .messageItem .bodyText .b-text-part div[data-x-div-type=html] div[data-x-div-type=html] {
height: 100%;
}
.messageView .b-content .messageItem .bodyText .b-text-part a { .messageView .b-content .messageItem .bodyText .b-text-part a {
color: blue; color: blue;
text-decoration: underline; text-decoration: underline;
@ -4953,20 +4962,35 @@ html.rl-message-fullscreen .messageView .b-content .buttonFull {
padding: 0; padding: 0;
height: 45px; height: 45px;
text-align: center; text-align: center;
width: 250px; width: 270px;
-webkit-box-shadow: inset 0 -1px 0 #cccccc; -webkit-box-shadow: inset 0 -1px 0 #cccccc;
-moz-box-shadow: inset 0 -1px 0 #cccccc; -moz-box-shadow: inset 0 -1px 0 #cccccc;
box-shadow: inset 0 -1px 0 #cccccc; box-shadow: inset 0 -1px 0 #cccccc;
} }
.b-contacts-content.modal .b-list-toopbar .e-search { .b-contacts-content.modal .b-list-toopbar .e-search {
margin-top: 7px; margin-top: 7px;
width: 245px;
}
.b-contacts-content.modal .b-list-footer-toopbar {
position: absolute;
left: 0;
bottom: 0;
height: 105px;
width: 270px;
background-color: #eee;
-webkit-box-shadow: inset 0 1px 0 #cccccc;
-moz-box-shadow: inset 0 1px 0 #cccccc;
box-shadow: inset 0 1px 0 #cccccc;
}
.b-contacts-content.modal .b-list-footer-toopbar .footer-pager {
padding: 8px 10px 0 0;
} }
.b-contacts-content.modal .b-list-content { .b-contacts-content.modal .b-list-content {
position: absolute; position: absolute;
top: 45px; top: 45px;
bottom: 60px; bottom: 105px;
left: 0; left: 0;
width: 250px; width: 270px;
overflow: hidden; overflow: hidden;
overflow-y: auto; overflow-y: auto;
} }
@ -4980,6 +5004,9 @@ html.rl-message-fullscreen .messageView .b-content .buttonFull {
font-size: 14px; font-size: 14px;
line-height: 13px; line-height: 13px;
background-color: #fff; background-color: #fff;
-webkit-box-shadow: inset 0 -1px 0 #cccccc;
-moz-box-shadow: inset 0 -1px 0 #cccccc;
box-shadow: inset 0 -1px 0 #cccccc;
} }
.b-contacts-content.modal .b-list-content .listEmptyList, .b-contacts-content.modal .b-list-content .listEmptyList,
.b-contacts-content.modal .b-list-content .listEmptyListLoading, .b-contacts-content.modal .b-list-content .listEmptyListLoading,
@ -5077,7 +5104,7 @@ html.rl-message-fullscreen .messageView .b-content .buttonFull {
position: absolute; position: absolute;
top: 0; top: 0;
bottom: 60px; bottom: 60px;
left: 250px; left: 270px;
right: 0; right: 0;
overflow: hidden; overflow: hidden;
overflow-y: auto; overflow-y: auto;

View file

@ -154,6 +154,12 @@ Consts.DataImages = {};
*/ */
Consts.Defaults.MessagesPerPage = 20; Consts.Defaults.MessagesPerPage = 20;
/**
* @const
* @type {number}
*/
Consts.Defaults.ContactsPerPage = 20;
/** /**
* @const * @const
* @type {Array} * @type {Array}
@ -1923,6 +1929,120 @@ Utils.resizeAndCrop = function (sUrl, iValue, fCallback)
oTempImg.src = sUrl; oTempImg.src = sUrl;
}; };
Utils.computedPagenatorHelper = function (koCurrentPage, koPageCount) {
return function() {
var
iPrev = 0,
iNext = 0,
iLimit = 2,
aResult = [],
iCurrentPage = koCurrentPage(),
iPageCount = koPageCount(),
/**
* @param {number} iIndex
* @param {boolean=} bPush
* @param {string=} sCustomName
*/
fAdd = function (iIndex, bPush, sCustomName) {
var oData = {
'current': iIndex === iCurrentPage,
'name': Utils.isUnd(sCustomName) ? iIndex.toString() : sCustomName.toString(),
'custom': Utils.isUnd(sCustomName) ? false : true,
'title': Utils.isUnd(sCustomName) ? '' : iIndex.toString(),
'value': iIndex.toString()
};
if (Utils.isUnd(bPush) ? true : !!bPush)
{
aResult.push(oData);
}
else
{
aResult.unshift(oData);
}
}
;
if (1 < iPageCount || (0 < iPageCount && iPageCount < iCurrentPage))
// if (0 < iPageCount && 0 < iCurrentPage)
{
if (iPageCount < iCurrentPage)
{
fAdd(iPageCount);
iPrev = iPageCount;
iNext = iPageCount;
}
else
{
if (3 >= iCurrentPage || iPageCount - 2 <= iCurrentPage)
{
iLimit += 2;
}
fAdd(iCurrentPage);
iPrev = iCurrentPage;
iNext = iCurrentPage;
}
while (0 < iLimit) {
iPrev -= 1;
iNext += 1;
if (0 < iPrev)
{
fAdd(iPrev, false);
iLimit--;
}
if (iPageCount >= iNext)
{
fAdd(iNext, true);
iLimit--;
}
else if (0 >= iPrev)
{
break;
}
}
if (3 === iPrev)
{
fAdd(2, false);
}
else if (3 < iPrev)
{
fAdd(Math.round((iPrev - 1) / 2), false, '...');
}
if (iPageCount - 2 === iNext)
{
fAdd(iPageCount - 1, true);
}
else if (iPageCount - 2 > iNext)
{
fAdd(Math.round((iPageCount + iNext) / 2), true, '...');
}
// first and last
if (1 < iPrev)
{
fAdd(1, false);
}
if (iPageCount > iNext)
{
fAdd(iPageCount, true);
}
}
return aResult;
};
};
// Base64 encode / decode // Base64 encode / decode
// http://www.webtoolkit.info/ // http://www.webtoolkit.info/

File diff suppressed because one or more lines are too long

View file

@ -154,6 +154,12 @@ Consts.DataImages = {};
*/ */
Consts.Defaults.MessagesPerPage = 20; Consts.Defaults.MessagesPerPage = 20;
/**
* @const
* @type {number}
*/
Consts.Defaults.ContactsPerPage = 20;
/** /**
* @const * @const
* @type {Array} * @type {Array}
@ -1923,6 +1929,120 @@ Utils.resizeAndCrop = function (sUrl, iValue, fCallback)
oTempImg.src = sUrl; oTempImg.src = sUrl;
}; };
Utils.computedPagenatorHelper = function (koCurrentPage, koPageCount) {
return function() {
var
iPrev = 0,
iNext = 0,
iLimit = 2,
aResult = [],
iCurrentPage = koCurrentPage(),
iPageCount = koPageCount(),
/**
* @param {number} iIndex
* @param {boolean=} bPush
* @param {string=} sCustomName
*/
fAdd = function (iIndex, bPush, sCustomName) {
var oData = {
'current': iIndex === iCurrentPage,
'name': Utils.isUnd(sCustomName) ? iIndex.toString() : sCustomName.toString(),
'custom': Utils.isUnd(sCustomName) ? false : true,
'title': Utils.isUnd(sCustomName) ? '' : iIndex.toString(),
'value': iIndex.toString()
};
if (Utils.isUnd(bPush) ? true : !!bPush)
{
aResult.push(oData);
}
else
{
aResult.unshift(oData);
}
}
;
if (1 < iPageCount || (0 < iPageCount && iPageCount < iCurrentPage))
// if (0 < iPageCount && 0 < iCurrentPage)
{
if (iPageCount < iCurrentPage)
{
fAdd(iPageCount);
iPrev = iPageCount;
iNext = iPageCount;
}
else
{
if (3 >= iCurrentPage || iPageCount - 2 <= iCurrentPage)
{
iLimit += 2;
}
fAdd(iCurrentPage);
iPrev = iCurrentPage;
iNext = iCurrentPage;
}
while (0 < iLimit) {
iPrev -= 1;
iNext += 1;
if (0 < iPrev)
{
fAdd(iPrev, false);
iLimit--;
}
if (iPageCount >= iNext)
{
fAdd(iNext, true);
iLimit--;
}
else if (0 >= iPrev)
{
break;
}
}
if (3 === iPrev)
{
fAdd(2, false);
}
else if (3 < iPrev)
{
fAdd(Math.round((iPrev - 1) / 2), false, '...');
}
if (iPageCount - 2 === iNext)
{
fAdd(iPageCount - 1, true);
}
else if (iPageCount - 2 > iNext)
{
fAdd(Math.round((iPageCount + iNext) / 2), true, '...');
}
// first and last
if (1 < iPrev)
{
fAdd(1, false);
}
if (iPageCount > iNext)
{
fAdd(iPageCount, true);
}
}
return aResult;
};
};
// Base64 encode / decode // Base64 encode / decode
// http://www.webtoolkit.info/ // http://www.webtoolkit.info/
@ -9060,10 +9180,19 @@ function PopupsContactsViewModel()
; ;
this.search = ko.observable(''); this.search = ko.observable('');
this.contactsCount = ko.observable(0);
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.currentContact = ko.observable(null); this.currentContact = ko.observable(null);
this.contactsPage = ko.observable(1);
this.contactsPageCount = ko.computed(function () {
var iPage = Math.ceil(this.contactsCount() / Consts.Defaults.ContactsPerPage);
return 0 >= iPage ? 1 : iPage;
}, this);
this.contactsPagenator = ko.computed(Utils.computedPagenatorHelper(this.contactsPage, this.contactsPageCount));
this.emptySelection = ko.observable(true); this.emptySelection = ko.observable(true);
this.viewClearSearch = ko.observable(false); this.viewClearSearch = ko.observable(false);
@ -9260,28 +9389,24 @@ function PopupsContactsViewModel()
var bV = this.viewHasNonEmptyRequaredProperties(); var bV = this.viewHasNonEmptyRequaredProperties();
return !this.viewSaving() && bV; return !this.viewSaving() && bV;
}); });
this.bDropPageAfterDelete = false;
} }
Utils.extendAsViewModel('PopupsContactsViewModel', PopupsContactsViewModel); Utils.extendAsViewModel('PopupsContactsViewModel', PopupsContactsViewModel);
PopupsContactsViewModel.prototype.addNewEmail = function () PopupsContactsViewModel.prototype.addNewEmail = function ()
{ {
// if (0 === this.viewPropertiesEmailsEmpty().length)
// {
var oItem = new ContactPropertyModel(Enums.ContactPropertyType.EmailPersonal, ''); var oItem = new ContactPropertyModel(Enums.ContactPropertyType.EmailPersonal, '');
oItem.focused(true); oItem.focused(true);
this.viewProperties.push(oItem); this.viewProperties.push(oItem);
// }
}; };
PopupsContactsViewModel.prototype.addNewPhone = function () PopupsContactsViewModel.prototype.addNewPhone = function ()
{ {
// if (0 === this.viewPropertiesPhonesEmpty().length)
// {
var oItem = new ContactPropertyModel(Enums.ContactPropertyType.PhonePersonal, ''); var oItem = new ContactPropertyModel(Enums.ContactPropertyType.PhonePersonal, '');
oItem.focused(true); oItem.focused(true);
this.viewProperties.push(oItem); this.viewProperties.push(oItem);
// }
}; };
PopupsContactsViewModel.prototype.removeCheckedOrSelectedContactsFromList = function () PopupsContactsViewModel.prototype.removeCheckedOrSelectedContactsFromList = function ()
@ -9290,6 +9415,7 @@ PopupsContactsViewModel.prototype.removeCheckedOrSelectedContactsFromList = func
self = this, self = this,
oKoContacts = this.contacts, oKoContacts = this.contacts,
oCurrentContact = this.currentContact(), oCurrentContact = this.currentContact(),
iCount = this.contacts().length,
aContacts = this.contactsCheckedOrSelected() aContacts = this.contactsCheckedOrSelected()
; ;
@ -9304,8 +9430,14 @@ PopupsContactsViewModel.prototype.removeCheckedOrSelectedContactsFromList = func
} }
oContact.deleted(true); oContact.deleted(true);
iCount--;
}); });
if (iCount <= 0)
{
this.bDropPageAfterDelete = true;
}
_.delay(function () { _.delay(function () {
_.each(aContacts, function (oContact) { _.each(aContacts, function (oContact) {
@ -9337,13 +9469,13 @@ PopupsContactsViewModel.prototype.deleteResponse = function (sResult, oData)
{ {
if (500 < (Enums.StorageResultType.Success === sResult && oData && oData.Time ? Utils.pInt(oData.Time) : 0)) if (500 < (Enums.StorageResultType.Success === sResult && oData && oData.Time ? Utils.pInt(oData.Time) : 0))
{ {
this.reloadContactList(); this.reloadContactList(this.bDropPageAfterDelete);
} }
else else
{ {
_.delay((function (self) { _.delay((function (self) {
return function () { return function () {
self.reloadContactList(); self.reloadContactList(self.bDropPageAfterDelete);
}; };
}(this)), 500); }(this)), 500);
} }
@ -9396,12 +9528,31 @@ PopupsContactsViewModel.prototype.populateViewContact = function (oContact)
this.viewProperties(aList); this.viewProperties(aList);
}; };
PopupsContactsViewModel.prototype.reloadContactList = function () /**
* @param {boolean=} bDropPagePosition = false
*/
PopupsContactsViewModel.prototype.reloadContactList = function (bDropPagePosition)
{ {
var self = this; var
self = this,
iOffset = (this.contactsPage() - 1) * Consts.Defaults.ContactsPerPage
;
this.bDropPageAfterDelete = false;
if (Utils.isUnd(bDropPagePosition) ? false : !!bDropPagePosition)
{
this.contactsPage(1);
iOffset = 0;
}
this.contacts.loading(true); this.contacts.loading(true);
RL.remote().contacts(function (sResult, oData) { RL.remote().contacts(function (sResult, oData) {
var aList = []; var
iCount = 0,
aList = []
;
if (Enums.StorageResultType.Success === sResult && oData && oData.Result && oData.Result.List) if (Enums.StorageResultType.Success === sResult && oData && oData.Result && oData.Result.List)
{ {
if (Utils.isNonEmptyArray(oData.Result.List)) if (Utils.isNonEmptyArray(oData.Result.List))
@ -9412,9 +9563,14 @@ PopupsContactsViewModel.prototype.reloadContactList = function ()
}); });
aList = _.compact(aList); aList = _.compact(aList);
iCount = Utils.pInt(oData.Result.Count);
iCount = 0 < iCount ? iCount : 0;
} }
} }
self.contactsCount(iCount);
self.contacts(aList); self.contacts(aList);
self.viewClearSearch('' !== self.search()); self.viewClearSearch('' !== self.search());
self.contacts.loading(false); self.contacts.loading(false);
@ -9424,7 +9580,7 @@ PopupsContactsViewModel.prototype.reloadContactList = function ()
self.contacts.setSelectedByUid('' + self.viewID()); self.contacts.setSelectedByUid('' + self.viewID());
} }
}, 0, 20, this.search()); }, iOffset, Consts.Defaults.ContactsPerPage, this.search());
}; };
PopupsContactsViewModel.prototype.onBuild = function (oDom) PopupsContactsViewModel.prototype.onBuild = function (oDom)
@ -9434,6 +9590,8 @@ PopupsContactsViewModel.prototype.onBuild = function (oDom)
this.selector.init(this.oContentVisible, this.oContentScrollable); this.selector.init(this.oContentVisible, this.oContentScrollable);
var self = this;
ko.computed(function () { ko.computed(function () {
var var
bModalVisibility = this.modalVisibility(), bModalVisibility = this.modalVisibility(),
@ -9441,12 +9599,23 @@ PopupsContactsViewModel.prototype.onBuild = function (oDom)
; ;
this.selector.useKeyboard(bModalVisibility && bUseKeyboardShortcuts); this.selector.useKeyboard(bModalVisibility && bUseKeyboardShortcuts);
}, this).extend({'notify': 'always'}); }, this).extend({'notify': 'always'});
oDom
.on('click', '.e-pagenator .e-page', function () {
var oPage = ko.dataFor(this);
if (oPage)
{
self.contactsPage(Utils.pInt(oPage.value));
self.reloadContactList();
}
})
;
}; };
PopupsContactsViewModel.prototype.onShow = function () PopupsContactsViewModel.prototype.onShow = function ()
{ {
kn.routeOff(); kn.routeOff();
this.reloadContactList(); this.reloadContactList(true);
}; };
PopupsContactsViewModel.prototype.onHide = function () PopupsContactsViewModel.prototype.onHide = function ()
@ -10404,118 +10573,7 @@ function MailBoxMessageListViewModel()
return '' === sValue ? '' : Utils.i18n('MESSAGE_LIST/SEARCH_RESULT_FOR', {'SEARCH': sValue}); return '' === sValue ? '' : Utils.i18n('MESSAGE_LIST/SEARCH_RESULT_FOR', {'SEARCH': sValue});
}); });
this.messageListPagenator = ko.computed(function () { this.messageListPagenator = ko.computed(Utils.computedPagenatorHelper(oData.messageListPage, oData.messageListPageCount));
var
iPrev = 0,
iNext = 0,
iLimit = 2,
aResult = [],
iCurrentPage = oData.messageListPage(),
iPageCount = oData.messageListPageCount(),
/**
* @param {number} iIndex
* @param {boolean=} bPush
* @param {string=} sCustomName
*/
fAdd = function (iIndex, bPush, sCustomName) {
var oData = {
'current': iIndex === iCurrentPage,
'name': Utils.isUnd(sCustomName) ? iIndex.toString() : sCustomName.toString(),
'custom': Utils.isUnd(sCustomName) ? false : true,
'title': Utils.isUnd(sCustomName) ? '' : iIndex.toString(),
'value': iIndex.toString()
};
if (Utils.isUnd(bPush) ? true : !!bPush)
{
aResult.push(oData);
}
else
{
aResult.unshift(oData);
}
}
;
if (1 < iPageCount || (0 < iPageCount && iPageCount < iCurrentPage))
// if (0 < iPageCount && 0 < iCurrentPage)
{
if (iPageCount < iCurrentPage)
{
fAdd(iPageCount);
iPrev = iPageCount;
iNext = iPageCount;
}
else
{
if (3 >= iCurrentPage || iPageCount - 2 <= iCurrentPage)
{
iLimit += 2;
}
fAdd(iCurrentPage);
iPrev = iCurrentPage;
iNext = iCurrentPage;
}
while (0 < iLimit) {
iPrev -= 1;
iNext += 1;
if (0 < iPrev)
{
fAdd(iPrev, false);
iLimit--;
}
if (iPageCount >= iNext)
{
fAdd(iNext, true);
iLimit--;
}
else if (0 >= iPrev)
{
break;
}
}
if (3 === iPrev)
{
fAdd(2, false);
}
else if (3 < iPrev)
{
fAdd(Math.round((iPrev - 1) / 2), false, '...');
}
if (iPageCount - 2 === iNext)
{
fAdd(iPageCount - 1, true);
}
else if (iPageCount - 2 > iNext)
{
fAdd(Math.round((iPageCount + iNext) / 2), true, '...');
}
// first and last
if (1 < iPrev)
{
fAdd(1, false);
}
if (iPageCount > iNext)
{
fAdd(iPageCount, true);
}
}
return aResult;
}, this);
this.checkAll = ko.computed({ this.checkAll = ko.computed({
'read': function () { 'read': function () {
@ -11152,7 +11210,7 @@ MailBoxMessageListViewModel.prototype.onBuild = function (oDom)
}); });
oDom oDom
.on('click', '.pagenator .page', function () { .on('click', '.e-pagenator .e-page', function () {
var oPage = ko.dataFor(this); var oPage = ko.dataFor(this);
if (oPage) if (oPage)
{ {
@ -12834,7 +12892,7 @@ function WebMailDataStorage()
this.messageListPageCount = ko.computed(function () { this.messageListPageCount = ko.computed(function () {
var iPage = Math.ceil(this.messageListCount() / this.messagesPerPage()); var iPage = Math.ceil(this.messageListCount() / this.messagesPerPage());
return 0 === iPage ? 1 : iPage; return 0 >= iPage ? 1 : iPage;
}, this); }, this);
this.mainMessageListSearch = ko.computed({ this.mainMessageListSearch = ko.computed({

File diff suppressed because one or more lines are too long