diff --git a/core/attributedef.class.inc.php b/core/attributedef.class.inc.php index 289809b70..0be3c436c 100644 --- a/core/attributedef.class.inc.php +++ b/core/attributedef.class.inc.php @@ -3430,7 +3430,10 @@ class AttributeEmailAddress extends AttributeString public function GetAsHTML($sValue, $oHostObject = null, $bLocalize = true) { if (empty($sValue)) return ''; - return ''.parent::GetAsHTML($sValue).''; + + $sUrlDecorationClass = utils::GetConfig()->Get('email_decoration_class'); + + return ''.parent::GetAsHTML($sValue).''; } } @@ -3454,6 +3457,35 @@ class AttributeIPAddress extends AttributeString } } +/** + * Specialization of a string: phone number + * + * @package iTopORM + */ +class AttributePhoneNumber extends AttributeString +{ + public function GetValidationPattern() + { + return $this->GetOptional('validation_pattern', '^'.utils::GetConfig()->Get('phone_number_validation_pattern').'$'); + } + + static public function GetFormFieldClass() + { + return '\\Combodo\\iTop\\Form\\Field\\PhoneField'; + } + + public function GetAsHTML($sValue, $oHostObject = null, $bLocalize = true) + { + if (empty($sValue)) return ''; + + $sUrlDecorationClass = utils::GetConfig()->Get('phone_number_decoration_class'); + $sUrlPattern = utils::GetConfig()->Get('phone_number_url_pattern'); + $sUrl = sprintf($sUrlPattern, $sValue); + + return ''.parent::GetAsHTML($sValue).''; + } +} + /** * Specialization of a string: OQL expression * diff --git a/core/config.class.inc.php b/core/config.class.inc.php index 76e617252..6110e07d9 100644 --- a/core/config.class.inc.php +++ b/core/config.class.inc.php @@ -764,14 +764,46 @@ class Config 'source_of_value' => '', 'show_in_conf_sample' => true, ), - 'email_validation_pattern' => array( - 'type' => 'string', - 'description' => 'Regular expression to validate/detect the format of an eMail address', - 'default' => "[a-zA-Z0-9._&'-]+@[a-zA-Z0-9.-]+\.[a-zA-Z0-9-]{2,}", - 'value' => '', - 'source_of_value' => '', - 'show_in_conf_sample' => true, - ), + 'email_validation_pattern' => array( + 'type' => 'string', + 'description' => 'Regular expression to validate/detect the format of an eMail address', + 'default' => "[a-zA-Z0-9._&'-]+@[a-zA-Z0-9.-]+\.[a-zA-Z0-9-]{2,}", + 'value' => '', + 'source_of_value' => '', + 'show_in_conf_sample' => true, + ), + 'email_decoration_class' => array( + 'type' => 'string', + 'description' => 'CSS class(es) to use as decoration for the HTML rendering of the attribute. eg. "fa fa-envelope" will put a mail icon.', + 'default' => 'fa fa-envelope', + 'value' => '', + 'source_of_value' => '', + 'show_in_conf_sample' => false, + ), + 'phone_number_validation_pattern' => array( + 'type' => 'string', + 'description' => 'Regular expression to validate/detect the format of a phone number', + 'default' => "[0-9.\-\ \+\(\)]+", + 'value' => '', + 'source_of_value' => '', + 'show_in_conf_sample' => false, + ), + 'phone_number_url_pattern' => array( + 'type' => 'string', + 'description' => 'Format for phone number url, use %1$s as a placeholder for the value. eg. "tel:%1$s" for regular phone applications or "callto:%1$s" for Skype. Default is "tel:%1$s".', + 'default' => 'tel:%1$s', + 'value' => '', + 'source_of_value' => '', + 'show_in_conf_sample' => false, + ), + 'phone_number_decoration_class' => array( + 'type' => 'string', + 'description' => 'CSS class(es) to use as decoration for the HTML rendering of the attribute. eg. "fa fa-phone" will put a phone icon.', + 'default' => 'fa fa-phone', + 'value' => '', + 'source_of_value' => '', + 'show_in_conf_sample' => false, + ), 'log_kpi_duration' => array( 'type' => 'integer', 'description' => 'Level of logging for troubleshooting performance issues (1 to enable, 2 +blame callers)', diff --git a/css/light-grey.css b/css/light-grey.css index e4f2d745c..d45892496 100644 --- a/css/light-grey.css +++ b/css/light-grey.css @@ -301,17 +301,15 @@ td a.no-arrow:hover { padding-left: 0px; background: inherit; } -td a.mailto, td a.mailto:visited { - text-decoration: none; - color: #000; - padding-left: 20px; - background: url(../images/mail.png?v=v2.5.0) no-repeat left; +td a:hover .text_decoration, td a:visited:hover .text_decoration { + color: #d56e14; } -td a.mailto:hover { - text-decoration: underline; +td a .text_decoration, td a:visited .text_decoration { + vertical-align: baseline; + text-decoration: none; color: #ea7d1e; - padding-left: 20px; - background: url(../images/mail.png?v=v2.5.0) no-repeat left; + margin-right: 8px; + transition: color 0.2s ease-in-out; } a.small_action { font-family: Tahoma, Verdana, Arial, Helvetica; diff --git a/css/light-grey.scss b/css/light-grey.scss index 67d080d37..65ea7be62 100644 --- a/css/light-grey.scss +++ b/css/light-grey.scss @@ -357,17 +357,21 @@ td a.no-arrow:hover { padding-left:0px; background: inherit; } -td a.mailto, td a.mailto:visited { - text-decoration:none; - color:#000000; - padding-left:20px; - background: url(../images/mail.png?v=#{$version}) no-repeat left; -} -td a.mailto:hover { - text-decoration:underline; - color:$highlight-color; - padding-left:20px; - background: url(../images/mail.png?v=#{$version}) no-repeat left; +td a, +td a:visited{ + &:hover{ + .text_decoration{ + color: darken($highlight-color, 6%); + } + } + + .text_decoration{ + vertical-align: baseline; + text-decoration: none; + color: $highlight-color; + margin-right: 8px; + transition: color 0.2s ease-in-out; + } } a.small_action { diff --git a/datamodels/2.x/itop-portal-base/portal/web/css/portal.css b/datamodels/2.x/itop-portal-base/portal/web/css/portal.css index 88db1ac0e..abf0b7d00 100644 --- a/datamodels/2.x/itop-portal-base/portal/web/css/portal.css +++ b/datamodels/2.x/itop-portal-base/portal/web/css/portal.css @@ -934,6 +934,10 @@ table .group-actions { color: #ea7d1e; font-size: 0.9em; } +.form_field .form_field_decoration { + vertical-align: baseline; + margin-right: 8px; +} /* ExternalKey */ .selectobject .input-group-addon { cursor: pointer; diff --git a/datamodels/2.x/itop-portal-base/portal/web/css/portal.scss b/datamodels/2.x/itop-portal-base/portal/web/css/portal.scss index cb9d00861..43eb89ff2 100644 --- a/datamodels/2.x/itop-portal-base/portal/web/css/portal.scss +++ b/datamodels/2.x/itop-portal-base/portal/web/css/portal.scss @@ -1016,6 +1016,10 @@ table .group-actions .item-action-wrapper .panel-body > p:last-child{ color: $brand-primary; font-size: 0.9em; } +.form_field .form_field_decoration{ + vertical-align: baseline; + margin-right: 8px; +} /* ExternalKey */ .selectobject .input-group-addon{ cursor: pointer; diff --git a/sources/autoload.php b/sources/autoload.php index 69da065be..4a9499ba3 100644 --- a/sources/autoload.php +++ b/sources/autoload.php @@ -33,6 +33,7 @@ require_once APPROOT . 'sources/form/field/labelfield.class.inc.php'; require_once APPROOT . 'sources/form/field/stringfield.class.inc.php'; require_once APPROOT . 'sources/form/field/urlfield.class.inc.php'; require_once APPROOT . 'sources/form/field/emailfield.class.inc.php'; +require_once APPROOT . 'sources/form/field/phonefield.class.inc.php'; require_once APPROOT . 'sources/form/field/passwordfield.class.inc.php'; require_once APPROOT . 'sources/form/field/datetimefield.class.inc.php'; require_once APPROOT . 'sources/form/field/durationfield.class.inc.php'; diff --git a/sources/form/field/emailfield.class.inc.php b/sources/form/field/emailfield.class.inc.php index 7994941b1..432d29c31 100644 --- a/sources/form/field/emailfield.class.inc.php +++ b/sources/form/field/emailfield.class.inc.php @@ -1,6 +1,6 @@ currentValue\">$sLabel"; + $sUrlDecorationClass = utils::GetConfig()->Get('email_decoration_class'); + + return "currentValue\">$sLabel"; } } diff --git a/sources/form/field/phonefield.class.inc.php b/sources/form/field/phonefield.class.inc.php new file mode 100644 index 000000000..973653c46 --- /dev/null +++ b/sources/form/field/phonefield.class.inc.php @@ -0,0 +1,45 @@ + + +namespace Combodo\iTop\Form\Field; + +use Str; +use utils; + +/** + * Description of PhoneField + * + * @author Guillaume Lajarige + */ +class PhoneField extends StringField +{ + public function GetDisplayValue() + { + $sLabel = Str::pure2html($this->currentValue); + if (strlen($sLabel) > 128) + { + // Truncate the length to 128 characters, by removing the middle + $sLabel = substr($sLabel, 0, 100).'.....'.substr($sLabel, -20); + } + + $sUrlDecorationClass = utils::GetConfig()->Get('phone_number_decoration_class'); + + return "currentValue\">$sLabel"; + } +} diff --git a/sources/renderer/bootstrap/bsformrenderer.class.inc.php b/sources/renderer/bootstrap/bsformrenderer.class.inc.php index 45a436e07..100c40ec9 100644 --- a/sources/renderer/bootstrap/bsformrenderer.class.inc.php +++ b/sources/renderer/bootstrap/bsformrenderer.class.inc.php @@ -46,6 +46,7 @@ class BsFormRenderer extends FormRenderer $this->AddSupportedField('StringField', 'BsSimpleFieldRenderer'); $this->AddSupportedField('UrlField', 'BsSimpleFieldRenderer'); $this->AddSupportedField('EmailField', 'BsSimpleFieldRenderer'); + $this->AddSupportedField('PhoneField', 'BsSimpleFieldRenderer'); $this->AddSupportedField('TextAreaField', 'BsSimpleFieldRenderer'); $this->AddSupportedField('CaseLogField', 'BsSimpleFieldRenderer'); $this->AddSupportedField('SelectField', 'BsSimpleFieldRenderer'); diff --git a/sources/renderer/bootstrap/fieldrenderer/bsfileuploadfieldrenderer.class.inc.php b/sources/renderer/bootstrap/fieldrenderer/bsfileuploadfieldrenderer.class.inc.php index 8929a7132..9a7da3e49 100644 --- a/sources/renderer/bootstrap/fieldrenderer/bsfileuploadfieldrenderer.class.inc.php +++ b/sources/renderer/bootstrap/fieldrenderer/bsfileuploadfieldrenderer.class.inc.php @@ -1,6 +1,6 @@ AddCssClass('form_field'); $oOutput->AddCssClass('form_field_' . $this->oField->GetDisplayMode()); $sObjectClass = get_class($this->oField->GetObject()); diff --git a/sources/renderer/bootstrap/fieldrenderer/bslinkedsetfieldrenderer.class.inc.php b/sources/renderer/bootstrap/fieldrenderer/bslinkedsetfieldrenderer.class.inc.php index 67e9ddbd2..ede59c8d5 100644 --- a/sources/renderer/bootstrap/fieldrenderer/bslinkedsetfieldrenderer.class.inc.php +++ b/sources/renderer/bootstrap/fieldrenderer/bslinkedsetfieldrenderer.class.inc.php @@ -1,6 +1,6 @@ AddCssClass('form_field'); $oOutput->AddCssClass('form_field_' . $this->oField->GetDisplayMode()); $sFieldMandatoryClass = ($this->oField->GetMandatory()) ? 'form_mandatory' : ''; diff --git a/sources/renderer/bootstrap/fieldrenderer/bsselectobjectfieldrenderer.class.inc.php b/sources/renderer/bootstrap/fieldrenderer/bsselectobjectfieldrenderer.class.inc.php index 52be11a86..aa250d08f 100644 --- a/sources/renderer/bootstrap/fieldrenderer/bsselectobjectfieldrenderer.class.inc.php +++ b/sources/renderer/bootstrap/fieldrenderer/bsselectobjectfieldrenderer.class.inc.php @@ -1,6 +1,6 @@ AddCssClass('form_field'); $oOutput->AddCssClass('form_field_' . $this->oField->GetDisplayMode()); $sFieldValueClass = $this->oField->GetSearch()->GetClass(); diff --git a/sources/renderer/bootstrap/fieldrenderer/bssimplefieldrenderer.class.inc.php b/sources/renderer/bootstrap/fieldrenderer/bssimplefieldrenderer.class.inc.php index 91a694d40..5990f1853 100644 --- a/sources/renderer/bootstrap/fieldrenderer/bssimplefieldrenderer.class.inc.php +++ b/sources/renderer/bootstrap/fieldrenderer/bssimplefieldrenderer.class.inc.php @@ -1,6 +1,6 @@ AddCssClass('form_field'); $oOutput->AddCssClass('form_field_' . $this->oField->GetDisplayMode()); $sFieldClass = get_class($this->oField); @@ -61,6 +62,7 @@ class BsSimpleFieldRenderer extends FieldRenderer case 'Combodo\\iTop\\Form\\Field\\StringField': case 'Combodo\\iTop\\Form\\Field\\UrlField': case 'Combodo\\iTop\\Form\\Field\\EmailField': + case 'Combodo\\iTop\\Form\\Field\\PhoneField': case 'Combodo\\iTop\\Form\\Field\\SelectField': case 'Combodo\\iTop\\Form\\Field\\MultipleSelectField': // Opening container @@ -101,6 +103,7 @@ EOF case 'Combodo\\iTop\\Form\\Field\\StringField': case 'Combodo\\iTop\\Form\\Field\\UrlField': case 'Combodo\\iTop\\Form\\Field\\EmailField': + case 'Combodo\\iTop\\Form\\Field\\PhoneField': $oOutput->AddHtml(''); break; @@ -220,6 +223,7 @@ EOF case 'Combodo\\iTop\\Form\\Field\\StringField': case 'Combodo\\iTop\\Form\\Field\\UrlField': case 'Combodo\\iTop\\Form\\Field\\EmailField': + case 'Combodo\\iTop\\Form\\Field\\PhoneField': case 'Combodo\\iTop\\Form\\Field\\TextAreaField': case 'Combodo\\iTop\\Form\\Field\\CaseLogField': case 'Combodo\\iTop\\Form\\Field\\SelectField': @@ -291,6 +295,7 @@ EOF case 'Combodo\\iTop\\Form\\Field\\StringField': case 'Combodo\\iTop\\Form\\Field\\UrlField': case 'Combodo\\iTop\\Form\\Field\\EmailField': + case 'Combodo\\iTop\\Form\\Field\\PhoneField': case 'Combodo\\iTop\\Form\\Field\\DateTimeField': case 'Combodo\\iTop\\Form\\Field\\DurationField': // Opening container @@ -308,7 +313,7 @@ EOF $oOutput->AddHtml(''); // Value - $bEncodeHtmlEntities = ( in_array($sFieldClass, array('Combodo\\iTop\\Form\\Field\\UrlField', 'Combodo\\iTop\\Form\\Field\\EmailField')) ) ? false : true; + $bEncodeHtmlEntities = ( in_array($sFieldClass, array('Combodo\\iTop\\Form\\Field\\UrlField', 'Combodo\\iTop\\Form\\Field\\EmailField', 'Combodo\\iTop\\Form\\Field\\PhoneField')) ) ? false : true; $oOutput->AddHtml('
'); $oOutput->AddHtml('
')->AddHtml($this->oField->GetDisplayValue(), $bEncodeHtmlEntities)->AddHtml('
'); $oOutput->AddHtml('
'); @@ -475,6 +480,7 @@ EOF case 'Combodo\\iTop\\Form\\Field\\StringField': case 'Combodo\\iTop\\Form\\Field\\UrlField': case 'Combodo\\iTop\\Form\\Field\\EmailField': + case 'Combodo\\iTop\\Form\\Field\\PhoneField': case 'Combodo\\iTop\\Form\\Field\\SelectField': case 'Combodo\\iTop\\Form\\Field\\MultipleSelectField': case 'Combodo\\iTop\\Form\\Field\\HiddenField': diff --git a/sources/renderer/bootstrap/fieldrenderer/bssubformfieldrenderer.class.inc.php b/sources/renderer/bootstrap/fieldrenderer/bssubformfieldrenderer.class.inc.php index 346f7652e..c0f8d5f83 100644 --- a/sources/renderer/bootstrap/fieldrenderer/bssubformfieldrenderer.class.inc.php +++ b/sources/renderer/bootstrap/fieldrenderer/bssubformfieldrenderer.class.inc.php @@ -1,5 +1,5 @@