mirror of
https://github.com/the-djmaze/snappymail.git
synced 2024-09-20 15:45:55 +08:00
Improved new AddressBook system
This commit is contained in:
parent
497193750b
commit
c9ad0ef170
|
@ -79,12 +79,12 @@ export class JCard {
|
|||
* @param arg the field, or a VCardProperty object
|
||||
* @param value the value for the VCardProperty object
|
||||
* @param params the parameters for the VCardProperty object
|
||||
* @param group the group for the VCardProperty object
|
||||
* @param type the type for the VCardProperty object
|
||||
*/
|
||||
set(arg, value, params, group)
|
||||
set(arg, value, params, type)
|
||||
{
|
||||
if (typeof arg === 'string') {
|
||||
arg = new VCardProperty(String(arg), value, params, group);
|
||||
arg = new VCardProperty(String(arg), value, params, type);
|
||||
}
|
||||
if (!(arg instanceof VCardProperty)) {
|
||||
throw new Error('invalid argument of VCard.set(), expects string arguments or a VCardProperty');
|
||||
|
@ -94,11 +94,11 @@ export class JCard {
|
|||
return arg;
|
||||
}
|
||||
|
||||
add(arg, value, params, group)
|
||||
add(arg, value, params, type)
|
||||
{
|
||||
// string arguments
|
||||
if (typeof arg === 'string') {
|
||||
arg = new VCardProperty(String(arg), value, params, group);
|
||||
arg = new VCardProperty(String(arg), value, params, type);
|
||||
}
|
||||
if (!(arg instanceof VCardProperty)) {
|
||||
throw new Error('invalid argument of VCard.add(), expects string arguments or a VCardProperty');
|
||||
|
|
|
@ -108,12 +108,16 @@ export class ContactModel extends AbstractModel {
|
|||
middleName: '', // MiddleName
|
||||
namePrefix: '', // NamePrefix
|
||||
nameSuffix: '', // NameSuffix
|
||||
nickname: null
|
||||
nickname: null,
|
||||
|
||||
encryptpref: '',
|
||||
signpref: ''
|
||||
});
|
||||
// this.email = koArrayWithDestroy();
|
||||
this.email = ko.observableArray();
|
||||
this.tel = ko.observableArray();
|
||||
this.url = ko.observableArray();
|
||||
this.adr = ko.observableArray();
|
||||
|
||||
this.addComputables({
|
||||
hasValidName: () => !!(this.givenName() || this.surName()),
|
||||
|
@ -156,7 +160,7 @@ export class ContactModel extends AbstractModel {
|
|||
|
||||
/**
|
||||
* @static
|
||||
* @param {FetchJsonContact} json
|
||||
* @param {jCard} json
|
||||
* @returns {?ContactModel}
|
||||
*/
|
||||
static reviveFromJson(json) {
|
||||
|
@ -181,6 +185,26 @@ export class ContactModel extends AbstractModel {
|
|||
});
|
||||
});
|
||||
|
||||
props = jCard.get('adr');
|
||||
props && props.forEach(prop => {
|
||||
contact.adr.push({
|
||||
street: ko.observable(prop.value[2]),
|
||||
street_ext: ko.observable(prop.value[1]),
|
||||
locality: ko.observable(prop.value[3]),
|
||||
region: ko.observable(prop.value[4]),
|
||||
postcode: ko.observable(prop.value[5]),
|
||||
pobox: ko.observable(prop.value[0]),
|
||||
country: ko.observable(prop.value[6]),
|
||||
preferred: ko.observable(prop.params.pref),
|
||||
type: ko.observable(prop.params.type) // HOME | WORK
|
||||
});
|
||||
});
|
||||
|
||||
props = jCard.getOne('x-Crypto');
|
||||
contact.signpref(props?.params.signpref || 'Ask');
|
||||
contact.encryptpref(props?.params.encryptpref || 'Ask');
|
||||
// contact.encryptpref(props?.params.allowed || 'PGP/INLINE,PGP/MIME,S/MIME,S/MIMEOpaque');
|
||||
|
||||
contact.jCard = jCard;
|
||||
}
|
||||
return contact;
|
||||
|
@ -249,6 +273,12 @@ export class ContactModel extends AbstractModel {
|
|||
values.forEach(value => value && jCard.add(field, value));
|
||||
});
|
||||
|
||||
jCard.set('x-Crypto', '', {
|
||||
allowed: 'PGP/INLINE,PGP/MIME,S/MIME,S/MIMEOpaque',
|
||||
signpref: this.signpref(),
|
||||
encryptpref: this.encryptpref()
|
||||
}, 'x-crypto');
|
||||
|
||||
// Done by server
|
||||
// jCard.set('rev', '2022-05-21T10:59:52Z')
|
||||
|
||||
|
|
|
@ -1,86 +0,0 @@
|
|||
import { pInt, pString } from 'Common/Utils';
|
||||
import { i18n } from 'Common/Translator';
|
||||
|
||||
import { AbstractModel } from 'Knoin/AbstractModel';
|
||||
|
||||
const trim = text => null == text ? "" : (text + "").trim();
|
||||
|
||||
/**
|
||||
* @enum {number}
|
||||
*/
|
||||
export const ContactPropertyType = {
|
||||
Unknown: 0,
|
||||
|
||||
FullName: 10,
|
||||
|
||||
FirstName: 15,
|
||||
LastName: 16,
|
||||
MiddleName: 17,
|
||||
Nick: 18,
|
||||
|
||||
NamePrefix: 20,
|
||||
NameSuffix: 21,
|
||||
|
||||
Email: 30,
|
||||
Phone: 31,
|
||||
Web: 32,
|
||||
|
||||
Birthday: 40,
|
||||
|
||||
Facebook: 90,
|
||||
Skype: 91,
|
||||
GitHub: 92,
|
||||
|
||||
Note: 110,
|
||||
|
||||
Custom: 250
|
||||
};
|
||||
|
||||
export class ContactPropertyModel extends AbstractModel {
|
||||
/**
|
||||
* @param {number=} type = Enums.ContactPropertyType.Unknown
|
||||
* @param {string=} typeStr = ''
|
||||
* @param {string=} value = ''
|
||||
* @param {boolean=} focused = false
|
||||
* @param {string=} placeholder = ''
|
||||
*/
|
||||
constructor(type = ContactPropertyType.Unknown, typeStr = '', value = '', focused = false, placeholder = '') {
|
||||
super();
|
||||
|
||||
this.addObservables({
|
||||
type: pInt(type),
|
||||
typeStr: pString(typeStr),
|
||||
focused: !!focused,
|
||||
value: pString(value),
|
||||
|
||||
placeholder: placeholder
|
||||
});
|
||||
|
||||
this.addComputables({
|
||||
placeholderValue: () => {
|
||||
const v = this.placeholder();
|
||||
return v ? i18n(v) : '';
|
||||
},
|
||||
|
||||
largeValue: () => ContactPropertyType.Note === this.type()
|
||||
});
|
||||
}
|
||||
|
||||
isType(type) {
|
||||
return this.type && type === this.type();
|
||||
}
|
||||
|
||||
isValid() {
|
||||
return this.value && !!trim(this.value());
|
||||
}
|
||||
|
||||
toJSON() {
|
||||
return {
|
||||
type: this.type(),
|
||||
typeStr: this.typeStr(),
|
||||
value: this.value()
|
||||
};
|
||||
}
|
||||
|
||||
// static reviveFromJson(json) {}
|
||||
}
|
|
@ -99,9 +99,10 @@ tr:hover .drag-handle {
|
|||
|
||||
.tabs {
|
||||
display: grid;
|
||||
grid-auto-columns: minmax(0, 1fr);
|
||||
}
|
||||
|
||||
.tabs input[type="radio"] {
|
||||
.tabs > input[type="radio"] {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: -9999px;
|
||||
|
@ -109,7 +110,7 @@ tr:hover .drag-handle {
|
|||
}
|
||||
|
||||
// Actual tabs
|
||||
.tabs label {
|
||||
.tabs > label {
|
||||
border: 1px solid transparent;
|
||||
border-radius: 4px 4px 0 0;
|
||||
cursor: pointer;
|
||||
|
@ -124,9 +125,9 @@ tr:hover .drag-handle {
|
|||
opacity: 0.8;
|
||||
}
|
||||
}
|
||||
.tabs [id^="tab"]:checked + label {
|
||||
.tabs > [id^="tab"]:checked + label {
|
||||
background-color: @white;
|
||||
border-color: #ddd #ddd transparent #ddd;
|
||||
border-color: rgba(128,128,128,.5) rgba(128,128,128,.5) transparent rgba(128,128,128,.5);
|
||||
opacity: 1;
|
||||
z-index: 1;
|
||||
}
|
||||
|
@ -140,6 +141,6 @@ tr:hover .drag-handle {
|
|||
visibility: hidden;
|
||||
}
|
||||
|
||||
.tabs [id^="tab"]:checked + label + .tab-content {
|
||||
.tabs > [id^="tab"]:checked + label + .tab-content {
|
||||
visibility: visible;
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
max-height: 700px;
|
||||
|
||||
.control-group {
|
||||
label {
|
||||
label.iconsize24 {
|
||||
padding-top: 0;
|
||||
width: 50px;
|
||||
}
|
||||
|
@ -135,12 +135,12 @@
|
|||
.b-view-content-toolbar {
|
||||
padding: 7px;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
left: @contacts-popup-left-width;
|
||||
height: 30px;
|
||||
text-align: right;
|
||||
border-bottom: 1px solid rgba(128,128,128,0.4);
|
||||
border-top: 1px solid rgba(128,128,128,0.4);
|
||||
|
||||
.button-save-contact {
|
||||
&.dirty:enabled {
|
||||
|
@ -148,12 +148,17 @@
|
|||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
.dropdown-menu.right-edge {
|
||||
top: auto;
|
||||
bottom: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.b-view-content {
|
||||
position: absolute;
|
||||
top: 45px;
|
||||
bottom: 0;
|
||||
top: 0;
|
||||
bottom: 45px;
|
||||
left: @contacts-popup-left-width;
|
||||
right: 0;
|
||||
overflow: auto;
|
||||
|
@ -176,19 +181,10 @@
|
|||
color: #999;
|
||||
}
|
||||
|
||||
.top-part {
|
||||
padding-top: 20px;
|
||||
}
|
||||
|
||||
.property-line {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.top-row {
|
||||
padding: 10px 0;
|
||||
height: 30px;
|
||||
}
|
||||
|
||||
input, textarea {
|
||||
box-shadow: none;
|
||||
border-color: #fff;
|
||||
|
@ -206,43 +202,28 @@
|
|||
border-color: #999;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.hasError {
|
||||
input {
|
||||
color: #ee5f5b;
|
||||
border-color: #ee5f5b;
|
||||
}
|
||||
.read-only-sign {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 20px;
|
||||
right: 40px;
|
||||
}
|
||||
|
||||
.read-only {
|
||||
span, .e-read-only-sign {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.e-save-trigger {
|
||||
position: absolute;
|
||||
top: 25px;
|
||||
left: 10px;
|
||||
}
|
||||
|
||||
.e-read-only-sign {
|
||||
input, textarea {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 20px;
|
||||
right: 40px;
|
||||
}
|
||||
}
|
||||
|
||||
.e-share-sign {
|
||||
position: absolute;
|
||||
top: 20px;
|
||||
right: 20px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
&.read-only {
|
||||
span, .e-read-only-sign {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
input, textarea, .e-share-sign {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
.tab-content {
|
||||
grid-column-end: 3;
|
||||
padding-top: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,6 @@
|
|||
}
|
||||
|
||||
.tab-content {
|
||||
grid-column-end: 6;
|
||||
grid-column-end: 5;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -107,7 +107,7 @@ export class ContactsPopupView extends AbstractViewPopup {
|
|||
}
|
||||
|
||||
newContact() {
|
||||
this.populateViewContact(null);
|
||||
this.populateViewContact();
|
||||
this.selectorContact(null);
|
||||
}
|
||||
|
||||
|
@ -252,11 +252,7 @@ export class ContactsPopupView extends AbstractViewPopup {
|
|||
* @param {?ContactModel} contact
|
||||
*/
|
||||
populateViewContact(contact) {
|
||||
if (!contact) {
|
||||
contact = new ContactModel;
|
||||
}
|
||||
this.contact(contact);
|
||||
|
||||
this.contact(contact || new ContactModel);
|
||||
this.hasChanges(false);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
<?php
|
||||
|
||||
use RainLoop\Providers\AddressBook\Classes\Contact;
|
||||
use RainLoop\Providers\AddressBook\Classes\Property;
|
||||
use RainLoop\Providers\AddressBook\Enumerations\PropertyType;
|
||||
|
||||
class KolabAddressBook implements \RainLoop\Providers\AddressBook\AddressBookInterface
|
||||
{
|
||||
|
@ -297,6 +295,7 @@ class KolabAddressBook implements \RainLoop\Providers\AddressBook\AddressBookInt
|
|||
$oParams->sSearch = 'from='.$sSearch;
|
||||
}
|
||||
$oParams->sSort = 'FROM';
|
||||
$oParams->bUseSortIfSupported = !!\RainLoop\Api::Actions()->Config()->Get('labs', 'use_imap_sort', true);
|
||||
// $oParams->iPrevUidNext = $this->GetActionParam('UidNext', 0);
|
||||
// $oParams->bUseThreads = false;
|
||||
|
||||
|
|
|
@ -4,11 +4,11 @@ class KolabPlugin extends \RainLoop\Plugins\AbstractPlugin
|
|||
{
|
||||
const
|
||||
NAME = 'Kolab',
|
||||
VERSION = '1.1',
|
||||
RELEASE = '2022-05-20',
|
||||
VERSION = '2.0',
|
||||
RELEASE = '2022-09-06',
|
||||
CATEGORY = 'Contacts',
|
||||
DESCRIPTION = 'Use an Address Book of Kolab.',
|
||||
REQUIRED = '2.16.2';
|
||||
REQUIRED = '2.18.0';
|
||||
|
||||
public function Init() : void
|
||||
{
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
|
||||
namespace RainLoop\Providers;
|
||||
|
||||
use RainLoop\Providers\AddressBook\Enumerations\PropertyType as PropertyType;
|
||||
|
||||
class AddressBook extends AbstractProvider
|
||||
{
|
||||
/**
|
||||
|
|
|
@ -2,11 +2,6 @@
|
|||
|
||||
namespace RainLoop\Providers\AddressBook\Classes;
|
||||
|
||||
use
|
||||
RainLoop\Providers\AddressBook\Enumerations\PropertyType,
|
||||
RainLoop\Providers\AddressBook\Classes\Property
|
||||
;
|
||||
|
||||
class Contact implements \JsonSerializable
|
||||
{
|
||||
/**
|
||||
|
|
|
@ -26,16 +26,6 @@ class Property implements \JsonSerializable
|
|||
*/
|
||||
public $Value;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $ValueLower = '';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $ValueCustom = '';
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
|
@ -48,101 +38,9 @@ class Property implements \JsonSerializable
|
|||
$this->TypeStr = $sTypeStr;
|
||||
}
|
||||
|
||||
public function IsName() : bool
|
||||
{
|
||||
return \in_array($this->Type, array(PropertyType::FULLNAME, PropertyType::FIRST_NAME,
|
||||
PropertyType::LAST_NAME, PropertyType::MIDDLE_NAME, PropertyType::NICK_NAME));
|
||||
}
|
||||
|
||||
public function IsEmail() : bool
|
||||
{
|
||||
return PropertyType::EMAIl === $this->Type;
|
||||
}
|
||||
|
||||
public function IsPhone() : bool
|
||||
{
|
||||
return PropertyType::PHONE === $this->Type;
|
||||
}
|
||||
|
||||
public function IsWeb() : bool
|
||||
{
|
||||
return PropertyType::WEB_PAGE === $this->Type;
|
||||
}
|
||||
|
||||
public function IsValueForLower() : bool
|
||||
{
|
||||
return $this->IsEmail() || $this->IsName() || $this->IsWeb();
|
||||
}
|
||||
|
||||
public function TypesAsArray() : array
|
||||
{
|
||||
$aResult = array();
|
||||
if (!empty($this->TypeStr))
|
||||
{
|
||||
$sTypeStr = \preg_replace('/[\s]+/', '', $this->TypeStr);
|
||||
$aResult = \explode(',', $sTypeStr);
|
||||
}
|
||||
|
||||
return $aResult;
|
||||
}
|
||||
|
||||
public function TypesUpperAsArray() : array
|
||||
{
|
||||
return \array_map('strtoupper', $this->TypesAsArray());
|
||||
}
|
||||
|
||||
public function UpdateDependentValues() : void
|
||||
{
|
||||
$this->Value = \trim($this->Value);
|
||||
$this->ValueCustom = \trim($this->ValueCustom);
|
||||
$this->TypeStr = \trim($this->TypeStr);
|
||||
$this->ValueLower = '';
|
||||
|
||||
if (\strlen($this->Value))
|
||||
{
|
||||
// lower
|
||||
if ($this->IsEmail())
|
||||
{
|
||||
$this->Value = \MailSo\Base\Utils::StrMailDomainToLower($this->Value);
|
||||
}
|
||||
|
||||
if ($this->IsName())
|
||||
{
|
||||
$this->Value = \MailSo\Base\Utils::StripSpaces($this->Value);
|
||||
}
|
||||
|
||||
// lower value for searching
|
||||
if ($this->IsValueForLower())
|
||||
{
|
||||
$this->ValueLower = (string) \mb_strtolower($this->Value, 'UTF-8');
|
||||
}
|
||||
|
||||
// phone value for searching
|
||||
if ($this->IsPhone())
|
||||
{
|
||||
$sPhone = \trim($this->Value);
|
||||
$sPhone = \preg_replace('/^[+]+/', '', $sPhone);
|
||||
$sPhone = \preg_replace('/[^\d]/', '', $sPhone);
|
||||
|
||||
$this->ValueCustom = \trim($sPhone);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[\ReturnTypeWillChange]
|
||||
public function jsonSerialize()
|
||||
{
|
||||
// Simple hack
|
||||
if ($this && $this->IsWeb())
|
||||
{
|
||||
$this->Value = \preg_replace('#(https?)\\\://#i', '$1://', $this->Value);
|
||||
}
|
||||
return array(
|
||||
'@Object' => 'Object/ContactProperty',
|
||||
'id' => $this->IdProperty,
|
||||
'type' => $this->Type,
|
||||
'typeStr' => $this->TypeStr,
|
||||
'value' => \MailSo\Base\Utils::Utf8Clear($this->Value)
|
||||
);
|
||||
throw new \Exception('Obsolete ' . __CLASS__ . '::jsonSerialize()');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,111 @@
|
|||
<?php
|
||||
|
||||
namespace RainLoop\Providers\AddressBook;
|
||||
|
||||
use
|
||||
RainLoop\Providers\AddressBook\Enumerations\PropertyType,
|
||||
RainLoop\Providers\AddressBook\Classes\Property
|
||||
;
|
||||
|
||||
class Legacy
|
||||
{
|
||||
/**
|
||||
* @param mixed $oProp
|
||||
*/
|
||||
private static function yieldPropertyHelper($oArrayProp, int $iType) : iterable
|
||||
{
|
||||
$aTmp = [];
|
||||
foreach ($oArrayProp as $oProp) {
|
||||
$sValue = \trim($oProp->getValue());
|
||||
if (\strlen($sValue)) {
|
||||
$oTypes = $oProp['TYPE'];
|
||||
$aTypes = $oTypes ? $oTypes->getParts() : array();
|
||||
$pref = 100;
|
||||
if (0 < $oProp['PREF']) {
|
||||
$pref = (int) $oProp['PREF'];
|
||||
}
|
||||
$aTmp[\substr(1000+$pref,-3) . $sValue] = new Property($iType, $sValue, \implode(',', $aTypes));
|
||||
}
|
||||
}
|
||||
\ksort($aTmp);
|
||||
foreach ($aTmp as $oProp) {
|
||||
yield $oProp;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $oProp
|
||||
*/
|
||||
private static function getPropertyValueHelper($oProp, bool $bOldVersion) : string
|
||||
{
|
||||
$sValue = \trim($oProp);
|
||||
if ($bOldVersion && !isset($oProp->parameters['CHARSET'])) {
|
||||
if (\strlen($sValue)) {
|
||||
$sEncValue = \utf8_encode($sValue);
|
||||
if (\strlen($sEncValue)) {
|
||||
$sValue = $sEncValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
return \MailSo\Base\Utils::Utf8Clear($sValue);
|
||||
}
|
||||
|
||||
public static function VCardToProperties(\Sabre\VObject\Component\VCard $oVCard) : iterable
|
||||
{
|
||||
yield new Property(PropertyType::JCARD, \json_encode($oVCard));
|
||||
|
||||
$bOldVersion = !empty($oVCard->VERSION) && \in_array((string) $oVCard->VERSION, array('2.1', '2.0', '1.0'));
|
||||
|
||||
if (isset($oVCard->FN) && '' !== \trim($oVCard->FN)) {
|
||||
$sValue = static::getPropertyValueHelper($oVCard->FN, $bOldVersion);
|
||||
yield new Property(PropertyType::FULLNAME, $sValue);
|
||||
}
|
||||
|
||||
if (isset($oVCard->N)) {
|
||||
$aNames = $oVCard->N->getParts();
|
||||
foreach ($aNames as $iIndex => $sValue) {
|
||||
$sValue = \trim($sValue);
|
||||
if ($bOldVersion && !isset($oVCard->N->parameters['CHARSET'])) {
|
||||
if (\strlen($sValue)) {
|
||||
$sEncValue = \utf8_encode($sValue);
|
||||
if (\strlen($sEncValue)) {
|
||||
$sValue = $sEncValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
$sValue = \MailSo\Base\Utils::Utf8Clear($sValue);
|
||||
if ($sValue) {
|
||||
switch ($iIndex) {
|
||||
case 0:
|
||||
yield new Property(PropertyType::LAST_NAME, $sValue);
|
||||
break;
|
||||
case 1:
|
||||
yield new Property(PropertyType::FIRST_NAME, $sValue);
|
||||
break;
|
||||
case 2:
|
||||
yield new Property(PropertyType::MIDDLE_NAME, $sValue);
|
||||
break;
|
||||
case 3:
|
||||
yield new Property(PropertyType::NAME_PREFIX, $sValue);
|
||||
break;
|
||||
case 4:
|
||||
yield new Property(PropertyType::NAME_SUFFIX, $sValue);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($oVCard->EMAIL)) {
|
||||
yield from static::yieldPropertyHelper($oVCard->EMAIL, PropertyType::EMAIl);
|
||||
}
|
||||
|
||||
if (isset($oVCard->URL)) {
|
||||
yield from static::yieldPropertyHelper($oVCard->URL, PropertyType::WEB_PAGE);
|
||||
}
|
||||
|
||||
if (isset($oVCard->TEL)) {
|
||||
yield from static::yieldPropertyHelper($oVCard->TEL, PropertyType::PHONE);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,7 +2,11 @@
|
|||
|
||||
namespace RainLoop\Providers\AddressBook;
|
||||
|
||||
use RainLoop\Providers\AddressBook\Enumerations\PropertyType;
|
||||
use
|
||||
Sabre\VObject\Component\VCard,
|
||||
RainLoop\Providers\AddressBook\Classes\Contact,
|
||||
RainLoop\Providers\AddressBook\Enumerations\PropertyType
|
||||
;
|
||||
|
||||
class PdoAddressBook
|
||||
extends \RainLoop\Common\PdoAbstract
|
||||
|
@ -265,7 +269,7 @@ class PdoAddressBook
|
|||
}
|
||||
}
|
||||
|
||||
if ($oVCard instanceof \Sabre\VObject\Component\VCard) {
|
||||
if ($oVCard instanceof VCard) {
|
||||
$oVCard->UID = $aData['uid'];
|
||||
|
||||
$oContact = null;
|
||||
|
@ -273,7 +277,7 @@ class PdoAddressBook
|
|||
$oContact = $this->GetContactByID($mExistingContactID);
|
||||
}
|
||||
if (!$oContact) {
|
||||
$oContact = new Classes\Contact();
|
||||
$oContact = new Contact();
|
||||
}
|
||||
|
||||
$oContact->setVCard($oVCard);
|
||||
|
@ -325,7 +329,7 @@ class PdoAddressBook
|
|||
return true;
|
||||
}
|
||||
|
||||
public function ContactSave(Classes\Contact $oContact) : bool
|
||||
public function ContactSave(Contact $oContact) : bool
|
||||
{
|
||||
if (1 > $this->iUserID) {
|
||||
return false;
|
||||
|
@ -390,9 +394,9 @@ class PdoAddressBook
|
|||
|
||||
if (0 < $iIdContact) {
|
||||
$aParams = array();
|
||||
foreach (Utils::VCardToProperties($oContact->vCard) as /* @var $oProp Classes\Property */ $oProp) {
|
||||
foreach (Legacy::VCardToProperties($oContact->vCard) as /* @var $oProp Classes\Property */ $oProp) {
|
||||
$iFreq = $oProp->Frec;
|
||||
if ($oProp->IsEmail() && isset($aFreq[$oProp->Value])) {
|
||||
if (PropertyType::EMAIl === $oProp->Type && isset($aFreq[$oProp->Value])) {
|
||||
$iFreq = $aFreq[$oProp->Value];
|
||||
}
|
||||
$aParams[] = array(
|
||||
|
@ -401,8 +405,8 @@ class PdoAddressBook
|
|||
':prop_type' => array($oProp->Type, \PDO::PARAM_INT),
|
||||
':prop_type_str' => array($oProp->TypeStr, \PDO::PARAM_STR),
|
||||
':prop_value' => array($oProp->Value, \PDO::PARAM_STR),
|
||||
':prop_value_lower' => array($oProp->ValueLower, \PDO::PARAM_STR),
|
||||
':prop_value_custom' => array($oProp->ValueCustom, \PDO::PARAM_STR),
|
||||
':prop_value_lower' => array(\mb_strtolower($oProp->Value, 'UTF-8'), \PDO::PARAM_STR),
|
||||
':prop_value_custom' => array('', \PDO::PARAM_STR),
|
||||
':prop_frec' => array($iFreq, \PDO::PARAM_INT),
|
||||
);
|
||||
}
|
||||
|
@ -475,7 +479,7 @@ class PdoAddressBook
|
|||
foreach ($aFetch as $aItem) {
|
||||
$iIdContact = $aItem && isset($aItem['id_contact']) ? (int) $aItem['id_contact'] : 0;
|
||||
if (0 < $iIdContact) {
|
||||
$oContact = new Classes\Contact();
|
||||
$oContact = new Contact();
|
||||
$oContact->id = (string) $iIdContact;
|
||||
$oContact->IdContactStr = (string) $aItem['id_contact_str'];
|
||||
// $oContact->Display = (string) $aItem['display'];
|
||||
|
@ -523,7 +527,7 @@ class PdoAddressBook
|
|||
$iPrevId = $iId;
|
||||
}
|
||||
if (!isset($aVCards[$iId])) {
|
||||
$aVCards[$iId] = new \Sabre\VObject\Component\VCard;
|
||||
$aVCards[$iId] = new VCard;
|
||||
}
|
||||
$oVCard = $aVCards[$iId];
|
||||
$oVCard->VERSION = '4.0';
|
||||
|
@ -684,7 +688,7 @@ class PdoAddressBook
|
|||
/**
|
||||
* @param mixed $mID
|
||||
*/
|
||||
public function GetContactByID($mID, bool $bIsStrID = false) : ?Classes\Contact
|
||||
public function GetContactByID($mID, bool $bIsStrID = false) : ?Contact
|
||||
{
|
||||
$mID = \trim($mID);
|
||||
|
||||
|
@ -962,16 +966,12 @@ class PdoAddressBook
|
|||
|
||||
if (\count($aEmailsToCreate)) {
|
||||
foreach ($aEmailsToCreate as $oEmail) {
|
||||
$oContact = new Classes\Contact();
|
||||
|
||||
$oVCard = new VCard;
|
||||
$bValid = false;
|
||||
if ('' !== \trim($oEmail->GetEmail())) {
|
||||
$oPropEmail = new Classes\Property();
|
||||
$oPropEmail->Type = Enumerations\PropertyType::EMAIl;
|
||||
$oPropEmail->Value = \trim($oEmail->GetEmail(true));
|
||||
|
||||
$oContact->Properties[] = $oPropEmail;
|
||||
$oVCard->add('EMAIL', \trim($oEmail->GetEmail(true)));
|
||||
$bValid = true;
|
||||
}
|
||||
|
||||
if ('' !== \trim($oEmail->GetDisplayName())) {
|
||||
$sFirst = $sLast = '';
|
||||
$sFullName = $oEmail->GetDisplayName();
|
||||
|
@ -982,25 +982,14 @@ class PdoAddressBook
|
|||
} else {
|
||||
$sFirst = $sFullName;
|
||||
}
|
||||
|
||||
if (\strlen($sFirst)) {
|
||||
$oPropName = new Classes\Property();
|
||||
$oPropName->Type = Enumerations\PropertyType::FIRST_NAME;
|
||||
$oPropName->Value = \trim($sFirst);
|
||||
|
||||
$oContact->Properties[] = $oPropName;
|
||||
}
|
||||
|
||||
if (\strlen($sLast)) {
|
||||
$oPropName = new Classes\Property();
|
||||
$oPropName->Type = Enumerations\PropertyType::LAST_NAME;
|
||||
$oPropName->Value = \trim($sLast);
|
||||
|
||||
$oContact->Properties[] = $oPropName;
|
||||
if (\strlen($sFirst) || \strlen($sLast)) {
|
||||
$oVCard->N = array($sLast, $sFirst, '', '', '');
|
||||
$bValid = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (\count($oContact->Properties)) {
|
||||
if ($bValid) {
|
||||
$oContact = new Contact();
|
||||
$oContact->setVCard($oVCard);
|
||||
$this->ContactSave($oContact);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,114 +2,8 @@
|
|||
|
||||
namespace RainLoop\Providers\AddressBook;
|
||||
|
||||
use
|
||||
RainLoop\Providers\AddressBook\Enumerations\PropertyType,
|
||||
RainLoop\Providers\AddressBook\Classes\Property
|
||||
;
|
||||
|
||||
|
||||
class Utils
|
||||
{
|
||||
/**
|
||||
* @param mixed $oProp
|
||||
*/
|
||||
private static function yieldPropertyHelper($oArrayProp, int $iType) : iterable
|
||||
{
|
||||
$aTmp = [];
|
||||
foreach ($oArrayProp as $oProp) {
|
||||
$sValue = \trim($oProp->getValue());
|
||||
if (\strlen($sValue)) {
|
||||
$oTypes = $oProp['TYPE'];
|
||||
$aTypes = $oTypes ? $oTypes->getParts() : array();
|
||||
$pref = 100;
|
||||
if (0 < $oProp['PREF']) {
|
||||
$pref = (int) $oProp['PREF'];
|
||||
}
|
||||
$aTmp[\substr(1000+$pref,-3) . $sValue] = new Property($iType, $sValue, \implode(',', $aTypes));
|
||||
}
|
||||
}
|
||||
\ksort($aTmp);
|
||||
foreach ($aTmp as $oProp) {
|
||||
yield $oProp;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $oProp
|
||||
*/
|
||||
private static function getPropertyValueHelper($oProp, bool $bOldVersion) : string
|
||||
{
|
||||
$sValue = \trim($oProp);
|
||||
if ($bOldVersion && !isset($oProp->parameters['CHARSET'])) {
|
||||
if (\strlen($sValue)) {
|
||||
$sEncValue = \utf8_encode($sValue);
|
||||
if (\strlen($sEncValue)) {
|
||||
$sValue = $sEncValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
return \MailSo\Base\Utils::Utf8Clear($sValue);
|
||||
}
|
||||
|
||||
public static function VCardToProperties(\Sabre\VObject\Component\VCard $oVCard) : iterable
|
||||
{
|
||||
yield new Property(PropertyType::JCARD, \json_encode($oVCard));
|
||||
|
||||
$bOldVersion = !empty($oVCard->VERSION) && \in_array((string) $oVCard->VERSION, array('2.1', '2.0', '1.0'));
|
||||
|
||||
if (isset($oVCard->FN) && '' !== \trim($oVCard->FN)) {
|
||||
$sValue = static::getPropertyValueHelper($oVCard->FN, $bOldVersion);
|
||||
yield new Property(PropertyType::FULLNAME, $sValue);
|
||||
}
|
||||
|
||||
if (isset($oVCard->N)) {
|
||||
$aNames = $oVCard->N->getParts();
|
||||
foreach ($aNames as $iIndex => $sValue) {
|
||||
$sValue = \trim($sValue);
|
||||
if ($bOldVersion && !isset($oVCard->N->parameters['CHARSET'])) {
|
||||
if (\strlen($sValue)) {
|
||||
$sEncValue = \utf8_encode($sValue);
|
||||
if (\strlen($sEncValue)) {
|
||||
$sValue = $sEncValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
$sValue = \MailSo\Base\Utils::Utf8Clear($sValue);
|
||||
if ($sValue) {
|
||||
switch ($iIndex) {
|
||||
case 0:
|
||||
yield new Property(PropertyType::LAST_NAME, $sValue);
|
||||
break;
|
||||
case 1:
|
||||
yield new Property(PropertyType::FIRST_NAME, $sValue);
|
||||
break;
|
||||
case 2:
|
||||
yield new Property(PropertyType::MIDDLE_NAME, $sValue);
|
||||
break;
|
||||
case 3:
|
||||
yield new Property(PropertyType::NAME_PREFIX, $sValue);
|
||||
break;
|
||||
case 4:
|
||||
yield new Property(PropertyType::NAME_SUFFIX, $sValue);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($oVCard->EMAIL)) {
|
||||
yield from static::yieldPropertyHelper($oVCard->EMAIL, PropertyType::EMAIl);
|
||||
}
|
||||
|
||||
if (isset($oVCard->URL)) {
|
||||
yield from static::yieldPropertyHelper($oVCard->URL, PropertyType::WEB_PAGE);
|
||||
}
|
||||
|
||||
if (isset($oVCard->TEL)) {
|
||||
yield from static::yieldPropertyHelper($oVCard->TEL, PropertyType::PHONE);
|
||||
}
|
||||
}
|
||||
|
||||
private static $aMap = array(
|
||||
'title' => 'FN',
|
||||
'name' => 'FN',
|
||||
|
@ -293,4 +187,11 @@ class Utils
|
|||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
public static function QrCode(string $sVcfData) : string
|
||||
{
|
||||
MECARD:N:djmaze;ORG:SnappyMail;TEL:+31012345678;URL:https\://snappymail.eu;EMAIL:info@snappymail.eu;ADR:address line;;
|
||||
VCARD
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
|
|
@ -174,6 +174,13 @@
|
|||
"SEARCHING_DESC": "يتم البحث..."
|
||||
},
|
||||
"CONTACTS": {
|
||||
"TAB_CONTACT": "Contact",
|
||||
"TAB_LOCATIONS": "Locations",
|
||||
"TAB_CRYPTO": "Crypto",
|
||||
"ASK": "Ask",
|
||||
"NEVER": "Never",
|
||||
"ALWAYS": "Always",
|
||||
"ALWAYS_IF_POSSIBLE": "Always if possible",
|
||||
"BUTTON_ADD_CONTACT": "إضافة جهة إتصال",
|
||||
"BUTTON_CREATE_CONTACT": "إنشاء",
|
||||
"BUTTON_UPDATE_CONTACT": "تحديث",
|
||||
|
|
|
@ -174,6 +174,13 @@
|
|||
"SEARCHING_DESC": "Търсене..."
|
||||
},
|
||||
"CONTACTS": {
|
||||
"TAB_CONTACT": "Contact",
|
||||
"TAB_LOCATIONS": "Locations",
|
||||
"TAB_CRYPTO": "Crypto",
|
||||
"ASK": "Ask",
|
||||
"NEVER": "Never",
|
||||
"ALWAYS": "Always",
|
||||
"ALWAYS_IF_POSSIBLE": "Always if possible",
|
||||
"BUTTON_ADD_CONTACT": "Добави контакт",
|
||||
"BUTTON_CREATE_CONTACT": "Създай",
|
||||
"BUTTON_UPDATE_CONTACT": "Обнови",
|
||||
|
|
|
@ -174,6 +174,13 @@
|
|||
"SEARCHING_DESC": "Hledám..."
|
||||
},
|
||||
"CONTACTS": {
|
||||
"TAB_CONTACT": "Contact",
|
||||
"TAB_LOCATIONS": "Locations",
|
||||
"TAB_CRYPTO": "Crypto",
|
||||
"ASK": "Ask",
|
||||
"NEVER": "Never",
|
||||
"ALWAYS": "Always",
|
||||
"ALWAYS_IF_POSSIBLE": "Always if possible",
|
||||
"BUTTON_ADD_CONTACT": "Přidat kontakt",
|
||||
"BUTTON_CREATE_CONTACT": "Vytvořit",
|
||||
"BUTTON_UPDATE_CONTACT": "Aktualizovat",
|
||||
|
|
|
@ -174,6 +174,13 @@
|
|||
"SEARCHING_DESC": "Søger..."
|
||||
},
|
||||
"CONTACTS": {
|
||||
"TAB_CONTACT": "Contact",
|
||||
"TAB_LOCATIONS": "Locations",
|
||||
"TAB_CRYPTO": "Crypto",
|
||||
"ASK": "Ask",
|
||||
"NEVER": "Never",
|
||||
"ALWAYS": "Always",
|
||||
"ALWAYS_IF_POSSIBLE": "Always if possible",
|
||||
"BUTTON_ADD_CONTACT": "Tilføj kontakt",
|
||||
"BUTTON_CREATE_CONTACT": "Ny kontakt",
|
||||
"BUTTON_UPDATE_CONTACT": "Opdater kontakt",
|
||||
|
|
|
@ -174,6 +174,13 @@
|
|||
"SEARCHING_DESC": "Suche läuft..."
|
||||
},
|
||||
"CONTACTS": {
|
||||
"TAB_CONTACT": "Contact",
|
||||
"TAB_LOCATIONS": "Locations",
|
||||
"TAB_CRYPTO": "Crypto",
|
||||
"ASK": "Ask",
|
||||
"NEVER": "Never",
|
||||
"ALWAYS": "Always",
|
||||
"ALWAYS_IF_POSSIBLE": "Always if possible",
|
||||
"BUTTON_ADD_CONTACT": "Kontakt hinzufügen",
|
||||
"BUTTON_CREATE_CONTACT": "Kontakt anlegen",
|
||||
"BUTTON_UPDATE_CONTACT": "Kontakt aktualisieren",
|
||||
|
|
|
@ -174,6 +174,13 @@
|
|||
"SEARCHING_DESC": "Αναζήτηση..."
|
||||
},
|
||||
"CONTACTS": {
|
||||
"TAB_CONTACT": "Contact",
|
||||
"TAB_LOCATIONS": "Locations",
|
||||
"TAB_CRYPTO": "Crypto",
|
||||
"ASK": "Ask",
|
||||
"NEVER": "Never",
|
||||
"ALWAYS": "Always",
|
||||
"ALWAYS_IF_POSSIBLE": "Always if possible",
|
||||
"BUTTON_ADD_CONTACT": "Προσθήκη επαφής",
|
||||
"BUTTON_CREATE_CONTACT": "Δημιουργία",
|
||||
"BUTTON_UPDATE_CONTACT": "Ενημέρωση",
|
||||
|
|
|
@ -174,6 +174,13 @@
|
|||
"SEARCHING_DESC": "Searching..."
|
||||
},
|
||||
"CONTACTS": {
|
||||
"TAB_CONTACT": "Contact",
|
||||
"TAB_LOCATIONS": "Locations",
|
||||
"TAB_CRYPTO": "Crypto",
|
||||
"ASK": "Ask",
|
||||
"NEVER": "Never",
|
||||
"ALWAYS": "Always",
|
||||
"ALWAYS_IF_POSSIBLE": "Always if possible",
|
||||
"BUTTON_ADD_CONTACT": "Add Contact",
|
||||
"BUTTON_CREATE_CONTACT": "Create",
|
||||
"BUTTON_UPDATE_CONTACT": "Update",
|
||||
|
|
|
@ -174,6 +174,13 @@
|
|||
"SEARCHING_DESC": "Searching..."
|
||||
},
|
||||
"CONTACTS": {
|
||||
"TAB_CONTACT": "Contact",
|
||||
"TAB_LOCATIONS": "Locations",
|
||||
"TAB_CRYPTO": "Crypto",
|
||||
"ASK": "Ask",
|
||||
"NEVER": "Never",
|
||||
"ALWAYS": "Always",
|
||||
"ALWAYS_IF_POSSIBLE": "Always if possible",
|
||||
"BUTTON_ADD_CONTACT": "Add Contact",
|
||||
"BUTTON_CREATE_CONTACT": "Create",
|
||||
"BUTTON_UPDATE_CONTACT": "Update",
|
||||
|
|
|
@ -174,6 +174,13 @@
|
|||
"SEARCHING_DESC": "Buscando..."
|
||||
},
|
||||
"CONTACTS": {
|
||||
"TAB_CONTACT": "Contact",
|
||||
"TAB_LOCATIONS": "Locations",
|
||||
"TAB_CRYPTO": "Crypto",
|
||||
"ASK": "Ask",
|
||||
"NEVER": "Never",
|
||||
"ALWAYS": "Always",
|
||||
"ALWAYS_IF_POSSIBLE": "Always if possible",
|
||||
"BUTTON_ADD_CONTACT": "Añadir Contacto",
|
||||
"BUTTON_CREATE_CONTACT": "Crear",
|
||||
"BUTTON_UPDATE_CONTACT": "Actualizar",
|
||||
|
|
|
@ -174,6 +174,13 @@
|
|||
"SEARCHING_DESC": "Otsin..."
|
||||
},
|
||||
"CONTACTS": {
|
||||
"TAB_CONTACT": "Contact",
|
||||
"TAB_LOCATIONS": "Locations",
|
||||
"TAB_CRYPTO": "Crypto",
|
||||
"ASK": "Ask",
|
||||
"NEVER": "Never",
|
||||
"ALWAYS": "Always",
|
||||
"ALWAYS_IF_POSSIBLE": "Always if possible",
|
||||
"BUTTON_ADD_CONTACT": "Lisa kontakt",
|
||||
"BUTTON_CREATE_CONTACT": "Lisa",
|
||||
"BUTTON_UPDATE_CONTACT": "Salvesta",
|
||||
|
|
|
@ -174,6 +174,13 @@
|
|||
"SEARCHING_DESC": "در حال جستجو..."
|
||||
},
|
||||
"CONTACTS": {
|
||||
"TAB_CONTACT": "Contact",
|
||||
"TAB_LOCATIONS": "Locations",
|
||||
"TAB_CRYPTO": "Crypto",
|
||||
"ASK": "Ask",
|
||||
"NEVER": "Never",
|
||||
"ALWAYS": "Always",
|
||||
"ALWAYS_IF_POSSIBLE": "Always if possible",
|
||||
"BUTTON_ADD_CONTACT": "اضافهکردن تماس",
|
||||
"BUTTON_CREATE_CONTACT": "ایجاد",
|
||||
"BUTTON_UPDATE_CONTACT": "بروزرسانی",
|
||||
|
|
|
@ -174,6 +174,13 @@
|
|||
"SEARCHING_DESC": "Hakee..."
|
||||
},
|
||||
"CONTACTS": {
|
||||
"TAB_CONTACT": "Contact",
|
||||
"TAB_LOCATIONS": "Locations",
|
||||
"TAB_CRYPTO": "Crypto",
|
||||
"ASK": "Ask",
|
||||
"NEVER": "Never",
|
||||
"ALWAYS": "Always",
|
||||
"ALWAYS_IF_POSSIBLE": "Always if possible",
|
||||
"BUTTON_ADD_CONTACT": "Lisää yhteystieto",
|
||||
"BUTTON_CREATE_CONTACT": "Luo",
|
||||
"BUTTON_UPDATE_CONTACT": "Päivitä",
|
||||
|
|
|
@ -174,6 +174,13 @@
|
|||
"SEARCHING_DESC": "Recherche..."
|
||||
},
|
||||
"CONTACTS": {
|
||||
"TAB_CONTACT": "Contact",
|
||||
"TAB_LOCATIONS": "Locations",
|
||||
"TAB_CRYPTO": "Crypto",
|
||||
"ASK": "Ask",
|
||||
"NEVER": "Never",
|
||||
"ALWAYS": "Always",
|
||||
"ALWAYS_IF_POSSIBLE": "Always if possible",
|
||||
"BUTTON_ADD_CONTACT": "Ajouter un contact",
|
||||
"BUTTON_CREATE_CONTACT": "Créer",
|
||||
"BUTTON_UPDATE_CONTACT": "Modifier",
|
||||
|
|
|
@ -174,6 +174,13 @@
|
|||
"SEARCHING_DESC": "Keresés..."
|
||||
},
|
||||
"CONTACTS": {
|
||||
"TAB_CONTACT": "Contact",
|
||||
"TAB_LOCATIONS": "Locations",
|
||||
"TAB_CRYPTO": "Crypto",
|
||||
"ASK": "Ask",
|
||||
"NEVER": "Never",
|
||||
"ALWAYS": "Always",
|
||||
"ALWAYS_IF_POSSIBLE": "Always if possible",
|
||||
"BUTTON_ADD_CONTACT": "Névjegy hozzáadás",
|
||||
"BUTTON_CREATE_CONTACT": "Létrehozás",
|
||||
"BUTTON_UPDATE_CONTACT": "Frissítés",
|
||||
|
|
|
@ -174,6 +174,13 @@
|
|||
"SEARCHING_DESC": "Pencarian..."
|
||||
},
|
||||
"CONTACTS": {
|
||||
"TAB_CONTACT": "Contact",
|
||||
"TAB_LOCATIONS": "Locations",
|
||||
"TAB_CRYPTO": "Crypto",
|
||||
"ASK": "Ask",
|
||||
"NEVER": "Never",
|
||||
"ALWAYS": "Always",
|
||||
"ALWAYS_IF_POSSIBLE": "Always if possible",
|
||||
"BUTTON_ADD_CONTACT": "Tambah Kontak",
|
||||
"BUTTON_CREATE_CONTACT": "Simpan",
|
||||
"BUTTON_UPDATE_CONTACT": "Perbarui",
|
||||
|
|
|
@ -174,6 +174,13 @@
|
|||
"SEARCHING_DESC": "Leita..."
|
||||
},
|
||||
"CONTACTS": {
|
||||
"TAB_CONTACT": "Contact",
|
||||
"TAB_LOCATIONS": "Locations",
|
||||
"TAB_CRYPTO": "Crypto",
|
||||
"ASK": "Ask",
|
||||
"NEVER": "Never",
|
||||
"ALWAYS": "Always",
|
||||
"ALWAYS_IF_POSSIBLE": "Always if possible",
|
||||
"BUTTON_ADD_CONTACT": "Bæta við tengilið",
|
||||
"BUTTON_CREATE_CONTACT": "Búa til",
|
||||
"BUTTON_UPDATE_CONTACT": "Uppfæra",
|
||||
|
|
|
@ -174,6 +174,13 @@
|
|||
"SEARCHING_DESC": "Cerca..."
|
||||
},
|
||||
"CONTACTS": {
|
||||
"TAB_CONTACT": "Contact",
|
||||
"TAB_LOCATIONS": "Locations",
|
||||
"TAB_CRYPTO": "Crypto",
|
||||
"ASK": "Ask",
|
||||
"NEVER": "Never",
|
||||
"ALWAYS": "Always",
|
||||
"ALWAYS_IF_POSSIBLE": "Always if possible",
|
||||
"BUTTON_ADD_CONTACT": "Aggiungi contatto",
|
||||
"BUTTON_CREATE_CONTACT": "Crea",
|
||||
"BUTTON_UPDATE_CONTACT": "Aggiorna",
|
||||
|
|
|
@ -174,6 +174,13 @@
|
|||
"SEARCHING_DESC": "検索中..."
|
||||
},
|
||||
"CONTACTS": {
|
||||
"TAB_CONTACT": "Contact",
|
||||
"TAB_LOCATIONS": "Locations",
|
||||
"TAB_CRYPTO": "Crypto",
|
||||
"ASK": "Ask",
|
||||
"NEVER": "Never",
|
||||
"ALWAYS": "Always",
|
||||
"ALWAYS_IF_POSSIBLE": "Always if possible",
|
||||
"BUTTON_ADD_CONTACT": "連絡先を追加",
|
||||
"BUTTON_CREATE_CONTACT": "作成",
|
||||
"BUTTON_UPDATE_CONTACT": "更新",
|
||||
|
|
|
@ -174,6 +174,13 @@
|
|||
"SEARCHING_DESC": "검색 중..."
|
||||
},
|
||||
"CONTACTS": {
|
||||
"TAB_CONTACT": "Contact",
|
||||
"TAB_LOCATIONS": "Locations",
|
||||
"TAB_CRYPTO": "Crypto",
|
||||
"ASK": "Ask",
|
||||
"NEVER": "Never",
|
||||
"ALWAYS": "Always",
|
||||
"ALWAYS_IF_POSSIBLE": "Always if possible",
|
||||
"BUTTON_ADD_CONTACT": "연락처 추가",
|
||||
"BUTTON_CREATE_CONTACT": "생성",
|
||||
"BUTTON_UPDATE_CONTACT": "업데이트",
|
||||
|
|
|
@ -174,6 +174,13 @@
|
|||
"SEARCHING_DESC": "Ieškome..."
|
||||
},
|
||||
"CONTACTS": {
|
||||
"TAB_CONTACT": "Contact",
|
||||
"TAB_LOCATIONS": "Locations",
|
||||
"TAB_CRYPTO": "Crypto",
|
||||
"ASK": "Ask",
|
||||
"NEVER": "Never",
|
||||
"ALWAYS": "Always",
|
||||
"ALWAYS_IF_POSSIBLE": "Always if possible",
|
||||
"BUTTON_ADD_CONTACT": "Pridėti kontaktą",
|
||||
"BUTTON_CREATE_CONTACT": "Sukurti",
|
||||
"BUTTON_UPDATE_CONTACT": "Atnaujinti",
|
||||
|
|
|
@ -174,6 +174,13 @@
|
|||
"SEARCHING_DESC": "Meklē..."
|
||||
},
|
||||
"CONTACTS": {
|
||||
"TAB_CONTACT": "Contact",
|
||||
"TAB_LOCATIONS": "Locations",
|
||||
"TAB_CRYPTO": "Crypto",
|
||||
"ASK": "Ask",
|
||||
"NEVER": "Never",
|
||||
"ALWAYS": "Always",
|
||||
"ALWAYS_IF_POSSIBLE": "Always if possible",
|
||||
"BUTTON_ADD_CONTACT": "Pievienot kontaktu",
|
||||
"BUTTON_CREATE_CONTACT": "Izveidot",
|
||||
"BUTTON_UPDATE_CONTACT": "Atjaunot",
|
||||
|
|
|
@ -174,6 +174,13 @@
|
|||
"SEARCHING_DESC": "Søker …"
|
||||
},
|
||||
"CONTACTS": {
|
||||
"TAB_CONTACT": "Contact",
|
||||
"TAB_LOCATIONS": "Locations",
|
||||
"TAB_CRYPTO": "Crypto",
|
||||
"ASK": "Ask",
|
||||
"NEVER": "Never",
|
||||
"ALWAYS": "Always",
|
||||
"ALWAYS_IF_POSSIBLE": "Always if possible",
|
||||
"BUTTON_ADD_CONTACT": "Legg til kontakt",
|
||||
"BUTTON_CREATE_CONTACT": "Lag",
|
||||
"BUTTON_UPDATE_CONTACT": "Oppdater",
|
||||
|
|
|
@ -174,6 +174,13 @@
|
|||
"SEARCHING_DESC": "Zoeken..."
|
||||
},
|
||||
"CONTACTS": {
|
||||
"TAB_CONTACT": "Contact",
|
||||
"TAB_LOCATIONS": "Locations",
|
||||
"TAB_CRYPTO": "Crypto",
|
||||
"ASK": "Ask",
|
||||
"NEVER": "Never",
|
||||
"ALWAYS": "Always",
|
||||
"ALWAYS_IF_POSSIBLE": "Always if possible",
|
||||
"BUTTON_ADD_CONTACT": "Contactpersoon Toevoegen",
|
||||
"BUTTON_CREATE_CONTACT": "Toevoegen",
|
||||
"BUTTON_UPDATE_CONTACT": "Bijwerken",
|
||||
|
|
|
@ -174,6 +174,13 @@
|
|||
"SEARCHING_DESC": "Wyszukiwanie..."
|
||||
},
|
||||
"CONTACTS": {
|
||||
"TAB_CONTACT": "Contact",
|
||||
"TAB_LOCATIONS": "Locations",
|
||||
"TAB_CRYPTO": "Crypto",
|
||||
"ASK": "Ask",
|
||||
"NEVER": "Never",
|
||||
"ALWAYS": "Always",
|
||||
"ALWAYS_IF_POSSIBLE": "Always if possible",
|
||||
"BUTTON_ADD_CONTACT": "Dodaj kontakt",
|
||||
"BUTTON_CREATE_CONTACT": "Utwórz",
|
||||
"BUTTON_UPDATE_CONTACT": "Zaktualizuj",
|
||||
|
|
|
@ -174,6 +174,13 @@
|
|||
"SEARCHING_DESC": "Procurando..."
|
||||
},
|
||||
"CONTACTS": {
|
||||
"TAB_CONTACT": "Contact",
|
||||
"TAB_LOCATIONS": "Locations",
|
||||
"TAB_CRYPTO": "Crypto",
|
||||
"ASK": "Ask",
|
||||
"NEVER": "Never",
|
||||
"ALWAYS": "Always",
|
||||
"ALWAYS_IF_POSSIBLE": "Always if possible",
|
||||
"BUTTON_ADD_CONTACT": "Adicionar Contato",
|
||||
"BUTTON_CREATE_CONTACT": "Criar",
|
||||
"BUTTON_UPDATE_CONTACT": "Atualizar",
|
||||
|
|
|
@ -174,6 +174,13 @@
|
|||
"SEARCHING_DESC": "A pesquisar..."
|
||||
},
|
||||
"CONTACTS": {
|
||||
"TAB_CONTACT": "Contact",
|
||||
"TAB_LOCATIONS": "Locations",
|
||||
"TAB_CRYPTO": "Crypto",
|
||||
"ASK": "Ask",
|
||||
"NEVER": "Never",
|
||||
"ALWAYS": "Always",
|
||||
"ALWAYS_IF_POSSIBLE": "Always if possible",
|
||||
"BUTTON_ADD_CONTACT": "Adicionar contacto",
|
||||
"BUTTON_CREATE_CONTACT": "Criar",
|
||||
"BUTTON_UPDATE_CONTACT": "Atualizar",
|
||||
|
|
|
@ -174,6 +174,13 @@
|
|||
"SEARCHING_DESC": "A pesquisar..."
|
||||
},
|
||||
"CONTACTS": {
|
||||
"TAB_CONTACT": "Contact",
|
||||
"TAB_LOCATIONS": "Locations",
|
||||
"TAB_CRYPTO": "Crypto",
|
||||
"ASK": "Ask",
|
||||
"NEVER": "Never",
|
||||
"ALWAYS": "Always",
|
||||
"ALWAYS_IF_POSSIBLE": "Always if possible",
|
||||
"BUTTON_ADD_CONTACT": "Adicionar contacto",
|
||||
"BUTTON_CREATE_CONTACT": "Criar",
|
||||
"BUTTON_UPDATE_CONTACT": "Atualizar",
|
||||
|
|
|
@ -174,6 +174,13 @@
|
|||
"SEARCHING_DESC": "Căutare..."
|
||||
},
|
||||
"CONTACTS": {
|
||||
"TAB_CONTACT": "Contact",
|
||||
"TAB_LOCATIONS": "Locations",
|
||||
"TAB_CRYPTO": "Crypto",
|
||||
"ASK": "Ask",
|
||||
"NEVER": "Never",
|
||||
"ALWAYS": "Always",
|
||||
"ALWAYS_IF_POSSIBLE": "Always if possible",
|
||||
"BUTTON_ADD_CONTACT": "Adugă un contact",
|
||||
"BUTTON_CREATE_CONTACT": "Salvează",
|
||||
"BUTTON_UPDATE_CONTACT": "Actualizează",
|
||||
|
|
|
@ -174,6 +174,13 @@
|
|||
"SEARCHING_DESC": "Поиск..."
|
||||
},
|
||||
"CONTACTS": {
|
||||
"TAB_CONTACT": "Contact",
|
||||
"TAB_LOCATIONS": "Locations",
|
||||
"TAB_CRYPTO": "Crypto",
|
||||
"ASK": "Ask",
|
||||
"NEVER": "Never",
|
||||
"ALWAYS": "Always",
|
||||
"ALWAYS_IF_POSSIBLE": "Always if possible",
|
||||
"BUTTON_ADD_CONTACT": "Добавить контакт",
|
||||
"BUTTON_CREATE_CONTACT": "Сохранить",
|
||||
"BUTTON_UPDATE_CONTACT": "Обновить",
|
||||
|
|
|
@ -174,6 +174,13 @@
|
|||
"SEARCHING_DESC": "Hľadám..."
|
||||
},
|
||||
"CONTACTS": {
|
||||
"TAB_CONTACT": "Contact",
|
||||
"TAB_LOCATIONS": "Locations",
|
||||
"TAB_CRYPTO": "Crypto",
|
||||
"ASK": "Ask",
|
||||
"NEVER": "Never",
|
||||
"ALWAYS": "Always",
|
||||
"ALWAYS_IF_POSSIBLE": "Always if possible",
|
||||
"BUTTON_ADD_CONTACT": "Pridať kontakt",
|
||||
"BUTTON_CREATE_CONTACT": "Vytvoriť",
|
||||
"BUTTON_UPDATE_CONTACT": "Aktualizovať",
|
||||
|
|
|
@ -174,6 +174,13 @@
|
|||
"SEARCHING_DESC": "Iskanje..."
|
||||
},
|
||||
"CONTACTS": {
|
||||
"TAB_CONTACT": "Contact",
|
||||
"TAB_LOCATIONS": "Locations",
|
||||
"TAB_CRYPTO": "Crypto",
|
||||
"ASK": "Ask",
|
||||
"NEVER": "Never",
|
||||
"ALWAYS": "Always",
|
||||
"ALWAYS_IF_POSSIBLE": "Always if possible",
|
||||
"BUTTON_ADD_CONTACT": "Dodaj stik",
|
||||
"BUTTON_CREATE_CONTACT": "Ustvari",
|
||||
"BUTTON_UPDATE_CONTACT": "Posodobi",
|
||||
|
|
|
@ -174,6 +174,13 @@
|
|||
"SEARCHING_DESC": "Söker..."
|
||||
},
|
||||
"CONTACTS": {
|
||||
"TAB_CONTACT": "Contact",
|
||||
"TAB_LOCATIONS": "Locations",
|
||||
"TAB_CRYPTO": "Crypto",
|
||||
"ASK": "Ask",
|
||||
"NEVER": "Never",
|
||||
"ALWAYS": "Always",
|
||||
"ALWAYS_IF_POSSIBLE": "Always if possible",
|
||||
"BUTTON_ADD_CONTACT": "Lägg till",
|
||||
"BUTTON_CREATE_CONTACT": "Ny",
|
||||
"BUTTON_UPDATE_CONTACT": "Uppdatera",
|
||||
|
|
|
@ -174,6 +174,13 @@
|
|||
"SEARCHING_DESC": "Aranıyor..."
|
||||
},
|
||||
"CONTACTS": {
|
||||
"TAB_CONTACT": "Contact",
|
||||
"TAB_LOCATIONS": "Locations",
|
||||
"TAB_CRYPTO": "Crypto",
|
||||
"ASK": "Ask",
|
||||
"NEVER": "Never",
|
||||
"ALWAYS": "Always",
|
||||
"ALWAYS_IF_POSSIBLE": "Always if possible",
|
||||
"BUTTON_ADD_CONTACT": "Ekle",
|
||||
"BUTTON_CREATE_CONTACT": "Oluştur",
|
||||
"BUTTON_UPDATE_CONTACT": "Güncelle",
|
||||
|
|
|
@ -174,6 +174,13 @@
|
|||
"SEARCHING_DESC": "Пошук..."
|
||||
},
|
||||
"CONTACTS": {
|
||||
"TAB_CONTACT": "Contact",
|
||||
"TAB_LOCATIONS": "Locations",
|
||||
"TAB_CRYPTO": "Crypto",
|
||||
"ASK": "Ask",
|
||||
"NEVER": "Never",
|
||||
"ALWAYS": "Always",
|
||||
"ALWAYS_IF_POSSIBLE": "Always if possible",
|
||||
"BUTTON_ADD_CONTACT": "Додати контакт",
|
||||
"BUTTON_CREATE_CONTACT": "Зберегти",
|
||||
"BUTTON_UPDATE_CONTACT": "Оновити",
|
||||
|
|
|
@ -174,6 +174,13 @@
|
|||
"SEARCHING_DESC": "Đang tìm kiếm..."
|
||||
},
|
||||
"CONTACTS": {
|
||||
"TAB_CONTACT": "Contact",
|
||||
"TAB_LOCATIONS": "Locations",
|
||||
"TAB_CRYPTO": "Crypto",
|
||||
"ASK": "Ask",
|
||||
"NEVER": "Never",
|
||||
"ALWAYS": "Always",
|
||||
"ALWAYS_IF_POSSIBLE": "Always if possible",
|
||||
"BUTTON_ADD_CONTACT": "Thêm liên hệ mới",
|
||||
"BUTTON_CREATE_CONTACT": "Tạo",
|
||||
"BUTTON_UPDATE_CONTACT": "Cập nhật",
|
||||
|
|
|
@ -174,6 +174,13 @@
|
|||
"SEARCHING_DESC": "搜索中……"
|
||||
},
|
||||
"CONTACTS": {
|
||||
"TAB_CONTACT": "Contact",
|
||||
"TAB_LOCATIONS": "Locations",
|
||||
"TAB_CRYPTO": "Crypto",
|
||||
"ASK": "Ask",
|
||||
"NEVER": "Never",
|
||||
"ALWAYS": "Always",
|
||||
"ALWAYS_IF_POSSIBLE": "Always if possible",
|
||||
"BUTTON_ADD_CONTACT": "添加联系人",
|
||||
"BUTTON_CREATE_CONTACT": "新增联系人",
|
||||
"BUTTON_UPDATE_CONTACT": "更新联系人",
|
||||
|
|
|
@ -174,6 +174,13 @@
|
|||
"SEARCHING_DESC": "搜索中..."
|
||||
},
|
||||
"CONTACTS": {
|
||||
"TAB_CONTACT": "Contact",
|
||||
"TAB_LOCATIONS": "Locations",
|
||||
"TAB_CRYPTO": "Crypto",
|
||||
"ASK": "Ask",
|
||||
"NEVER": "Never",
|
||||
"ALWAYS": "Always",
|
||||
"ALWAYS_IF_POSSIBLE": "Always if possible",
|
||||
"BUTTON_ADD_CONTACT": "添加連絡人",
|
||||
"BUTTON_CREATE_CONTACT": "新增連絡人",
|
||||
"BUTTON_UPDATE_CONTACT": "更新連絡人",
|
||||
|
|
|
@ -72,58 +72,19 @@
|
|||
<!-- ko template: { name: 'Paginator', data: contactsPaginator } --><!-- /ko -->
|
||||
</div>
|
||||
</div>
|
||||
<div class="b-view-content-toolbar btn-toolbar" data-bind="i18nUpdate: contact">
|
||||
<!-- ko with: contact -->
|
||||
<div class="btn-group">
|
||||
<button class="btn button-save-contact" data-bind="visible: !readOnly(), command: $root.saveCommand, css: {'dirty': $root.hasChanges}">
|
||||
<i data-bind="css: {'icon-ok': !$root.isSaving(), 'icon-spinner': $root.isSaving()}"></i>
|
||||
<span data-i18n="CONTACTS/BUTTON_CREATE_CONTACT" data-bind="visible: !id()"></span>
|
||||
<span data-i18n="CONTACTS/BUTTON_UPDATE_CONTACT" data-bind="visible: id"></span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="btn-group dropdown" data-bind="visible: !readOnly(), registerBootstrapDropdown: true">
|
||||
<a id="button-add-prop-dropdown-id" href="#" class="btn dropdown-toggle" data-i18n="CONTACTS/ADD_MENU_LABEL"></a>
|
||||
<menu class="dropdown-menu right-edge" style="text-align: left" role="menu" aria-labelledby="button-add-prop-dropdown-id">
|
||||
<li role="presentation">
|
||||
<a href="#" data-bind="click: addEmail">
|
||||
<i class="icon-none"></i>
|
||||
<span data-i18n="GLOBAL/EMAIL"></span>
|
||||
</a>
|
||||
</li>
|
||||
<li role="presentation">
|
||||
<a href="#" data-bind="click: addTel">
|
||||
<i class="icon-none"></i>
|
||||
<span data-i18n="CONTACTS/ADD_MENU_PHONE"></span>
|
||||
</a>
|
||||
</li>
|
||||
<li role="presentation">
|
||||
<a href="#" data-bind="click: addUrl">
|
||||
<i class="icon-none"></i>
|
||||
<span data-i18n="CONTACTS/ADD_MENU_URL"></span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="dividerbar" role="presentation">
|
||||
<a href="#" data-bind="click: addNickname">
|
||||
<i class="icon-none"></i>
|
||||
<span data-i18n="CONTACTS/ADD_MENU_NICKNAME"></span>
|
||||
</a>
|
||||
</li>
|
||||
<!--
|
||||
<li role="presentation">
|
||||
<a href="#" data-bind="click: addNewAddress">
|
||||
<span data-i18n="CONTACTS/ADD_MENU_ADDRESS"></span>
|
||||
</a>
|
||||
</li>-->
|
||||
</menu>
|
||||
</div>
|
||||
<!-- /ko -->
|
||||
</div>
|
||||
<div class="b-view-content">
|
||||
<div class="b-contact-view-desc" data-bind="visible: !contact"
|
||||
<div class="b-view-content" data-bind="css: {'read-only': contact() && contact().readOnly()}">
|
||||
<div class="b-contact-view-desc" data-bind="visible: !contact()"
|
||||
data-i18n="CONTACTS/CONTACT_VIEW_DESC"></div>
|
||||
<div data-bind="visible: contact, i18nUpdate: contact">
|
||||
<div class="tabs" data-bind="visible: contact, i18nUpdate: contact">
|
||||
<!-- ko with: contact -->
|
||||
<div class="form-horizontal top-part" data-bind="css: {'read-only': readOnly}">
|
||||
<input type="radio" name="contacttabs" id="tab-contact" checked>
|
||||
<label for="tab-contact"
|
||||
role="tab"
|
||||
aria-selected="true"
|
||||
aria-controls="panel1"
|
||||
tabindex="0"
|
||||
data-i18n="CONTACTS/TAB_CONTACT"></label>
|
||||
<div class="form-horizontal tab-content" role="tabpanel" aria-hidden="false">
|
||||
<div class="control-group" data-bind="visible: !readOnly() || hasValidName()">
|
||||
<label class="fontastic iconsize24">👤</label>
|
||||
<div>
|
||||
|
@ -210,10 +171,107 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- /ko -->
|
||||
<!--
|
||||
<div class="e-read-only-sign fontastic iconsize24" data-i18n="[title]CONTACTS/LABEL_READ_ONLY">🔒</div>
|
||||
<input type="radio" name="contacttabs" id="tab-contact-locations">
|
||||
<label for="tab-contact-locations"
|
||||
role="tab"
|
||||
aria-selected="false"
|
||||
aria-controls="panel3"
|
||||
tabindex="0"
|
||||
data-i18n="CONTACTS/TAB_LOCATIONS"></label>
|
||||
<div class="form-horizontal tab-content" role="tabpanel" aria-hidden="false">
|
||||
<div data-bind="foreach: adr">
|
||||
<div class="control-group">
|
||||
<div data-bind="text: type"></div>
|
||||
<div data-bind="text: street"></div>
|
||||
<div data-bind="text: street_ext"></div>
|
||||
<div data-bind="text: locality"></div>
|
||||
<div data-bind="text: region"></div>
|
||||
<div data-bind="text: postcode"></div>
|
||||
<div data-bind="text: pobox"></div>
|
||||
<div data-bind="text: country"></div>
|
||||
<div data-bind="text: preferred"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
-->
|
||||
<input type="radio" name="contacttabs" id="tab-contact-crypto">
|
||||
<label for="tab-contact-crypto"
|
||||
role="tab"
|
||||
aria-selected="false"
|
||||
aria-controls="panel3"
|
||||
tabindex="0"
|
||||
data-i18n="CONTACTS/TAB_CRYPTO"></label>
|
||||
<div class="form-horizontal tab-content" role="tabpanel" aria-hidden="false">
|
||||
<div class="control-group">
|
||||
<label>Sign</label>
|
||||
<select name="x-crypto[signpref]" data-bind="value: signpref">
|
||||
<option value="Ask" data-i18n="CONTACTS/ASK"></option>
|
||||
<option value="Never" data-i18n="CONTACTS/NEVER"></option>
|
||||
<option value="Always" data-i18n="CONTACTS/ALWAYS"></option>
|
||||
<option value="IfPossible" data-i18n="CONTACTS/ALWAYS_IF_POSSIBLE"></option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<label>Encrypt</label>
|
||||
<select name="x-crypto[encryptpref]" data-bind="value: encryptpref">
|
||||
<option value="Ask" data-i18n="CONTACTS/ASK"></option>
|
||||
<option value="Never" data-i18n="CONTACTS/NEVER"></option>
|
||||
<option value="Always" data-i18n="CONTACTS/ALWAYS"></option>
|
||||
<option value="IfPossible" data-i18n="CONTACTS/ALWAYS_IF_POSSIBLE"></option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<!-- /ko -->
|
||||
</div>
|
||||
</div>
|
||||
<div class="b-view-content-toolbar btn-toolbar" data-bind="i18nUpdate: contact">
|
||||
<!-- ko with: contact -->
|
||||
<div class="btn-group">
|
||||
<button class="btn button-save-contact" data-bind="visible: !readOnly(), command: $root.saveCommand, css: {'dirty': $root.hasChanges}">
|
||||
<i data-bind="css: {'icon-ok': !$root.isSaving(), 'icon-spinner': $root.isSaving()}"></i>
|
||||
<span data-i18n="CONTACTS/BUTTON_CREATE_CONTACT" data-bind="visible: !id()"></span>
|
||||
<span data-i18n="CONTACTS/BUTTON_UPDATE_CONTACT" data-bind="visible: id"></span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="btn-group dropdown" data-bind="visible: !readOnly(), registerBootstrapDropdown: true">
|
||||
<a id="button-add-prop-dropdown-id" href="#" class="btn dropdown-toggle" data-i18n="CONTACTS/ADD_MENU_LABEL"></a>
|
||||
<menu class="dropdown-menu right-edge" style="text-align: left" role="menu" aria-labelledby="button-add-prop-dropdown-id">
|
||||
<li role="presentation">
|
||||
<a href="#" data-bind="click: addEmail">
|
||||
<i class="icon-none"></i>
|
||||
<span data-i18n="GLOBAL/EMAIL"></span>
|
||||
</a>
|
||||
</li>
|
||||
<li role="presentation">
|
||||
<a href="#" data-bind="click: addTel">
|
||||
<i class="icon-none"></i>
|
||||
<span data-i18n="CONTACTS/ADD_MENU_PHONE"></span>
|
||||
</a>
|
||||
</li>
|
||||
<li role="presentation">
|
||||
<a href="#" data-bind="click: addUrl">
|
||||
<i class="icon-none"></i>
|
||||
<span data-i18n="CONTACTS/ADD_MENU_URL"></span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="dividerbar" role="presentation">
|
||||
<a href="#" data-bind="click: addNickname">
|
||||
<i class="icon-none"></i>
|
||||
<span data-i18n="CONTACTS/ADD_MENU_NICKNAME"></span>
|
||||
</a>
|
||||
</li>
|
||||
<!--
|
||||
<li role="presentation">
|
||||
<a href="#" data-bind="click: addNewAddress">
|
||||
<span data-i18n="CONTACTS/ADD_MENU_ADDRESS"></span>
|
||||
</a>
|
||||
</li>-->
|
||||
</menu>
|
||||
</div>
|
||||
<!--
|
||||
<div class="read-only-sign fontastic iconsize24" data-bind="visible: readOnly" data-i18n="[title]CONTACTS/LABEL_READ_ONLY">🔒</div>
|
||||
-->
|
||||
<!-- /ko -->
|
||||
</div>
|
||||
</div>
|
||||
|
|
Loading…
Reference in a new issue