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

File diff suppressed because it is too large Load diff

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,11 +1,11 @@
<div class="popups">
<div class="modal hide b-contacts-content" data-bind="modal: modalVisibility">
<div class="modal-header b-header-toolbar g-ui-user-select-none">
<button type="button" class="close" data-bind="command: cancelCommand">&times;</button>
<div class="btn-toolbar">
<div class="btn-group">
<a class="btn button-create-contact" data-bind="command: newCommand">
<i class="icon-plus"></i>
@ -126,25 +126,41 @@
<ul class="dropdown-menu g-ui-menu" style="text-align: left" tabindex="-1" role="menu" aria-labelledby="button-add-prop-dropdown-id">
<li class="e-item" role="presentation">
<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>
</a>
</li>
<li class="e-item" role="presentation">
<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>
</a>
</li>
<li class="e-item" role="presentation">
<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>
</a>
</li>
<li class="divider" role="presentation"></li>
<li class="e-item" role="presentation">
<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>
</a>
</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">
<a class="e-link menuitem" href="#" tabindex="-1" data-bind="click: addNewAddress">
<span class="i18n" data-i18n-text="CONTACTS/ADD_MENU_ADDRESS"></span>
@ -247,6 +263,18 @@
</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="controls fix-width">
<br />
@ -254,12 +282,12 @@
</div>
</div>
</div>
<!-- <div class="e-read-only-sign">
<i class="icon-lock iconsize24" data-tooltip-placement="left" data-bind="tooltip: 'CONTACTS/LABEL_READ_ONLY'"></i>
</div>-->
</div>
</div>
</div>

View file

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

View file

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

View file

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

File diff suppressed because one or more lines are too long

View file

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

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long