1<?php 2 3// Copyright (C) 2010-2018 Combodo SARL 4// 5// This file is part of iTop. 6// 7// iTop is free software; you can redistribute it and/or modify 8// it under the terms of the GNU Affero General Public License as published by 9// the Free Software Foundation, either version 3 of the License, or 10// (at your option) any later version. 11// 12// iTop is distributed in the hope that it will be useful, 13// but WITHOUT ANY WARRANTY; without even the implied warranty of 14// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15// GNU Affero General Public License for more details. 16// 17// You should have received a copy of the GNU Affero General Public License 18// along with iTop. If not, see <http://www.gnu.org/licenses/> 19 20namespace Combodo\iTop\Renderer\Bootstrap\FieldRenderer; 21 22use utils; 23use Dict; 24use UserRights; 25use AttributeDateTime; 26use AttributeText; 27use InlineImage; 28use Combodo\iTop\Renderer\FieldRenderer; 29use Combodo\iTop\Renderer\RenderingOutput; 30use Combodo\iTop\Form\Field\TextAreaField; 31use Combodo\iTop\Form\Field\MultipleChoicesField; 32 33/** 34 * Description of BsSimpleFieldRenderer 35 * 36 * @author Guillaume Lajarige <guillaume.lajarige@combodo.com> 37 */ 38class BsSimpleFieldRenderer extends FieldRenderer 39{ 40 41 /** 42 * Returns a RenderingOutput for the FieldRenderer's Field 43 * 44 * @return \Combodo\iTop\Renderer\RenderingOutput 45 * 46 * @throws \Exception 47 */ 48 public function Render() 49 { 50 $oOutput = new RenderingOutput(); 51 $oOutput->AddCssClass('form_field_' . $this->oField->GetDisplayMode()); 52 53 $sFieldClass = get_class($this->oField); 54 $sFieldMandatoryClass = ($this->oField->GetMandatory()) ? 'form_mandatory' : ''; 55 56 // Rendering field in edition mode 57 if (!$this->oField->GetReadOnly() && !$this->oField->GetHidden()) 58 { 59 // HTML content 60 switch ($sFieldClass) 61 { 62 case 'Combodo\\iTop\\Form\\Field\\DateTimeField': 63 case 'Combodo\\iTop\\Form\\Field\\PasswordField': 64 case 'Combodo\\iTop\\Form\\Field\\StringField': 65 case 'Combodo\\iTop\\Form\\Field\\UrlField': 66 case 'Combodo\\iTop\\Form\\Field\\EmailField': 67 case 'Combodo\\iTop\\Form\\Field\\PhoneField': 68 case 'Combodo\\iTop\\Form\\Field\\SelectField': 69 case 'Combodo\\iTop\\Form\\Field\\MultipleSelectField': 70 // Opening container 71 $oOutput->AddHtml('<div class="form-group form_group_small ' . $sFieldMandatoryClass . '">'); 72 73 // Label 74 $oOutput->AddHtml('<div class="form_field_label">'); 75 if ($this->oField->GetLabel() !== '') 76 { 77 $oOutput->AddHtml('<label for="' . $this->oField->GetGlobalId() . '" class="control-label">')->AddHtml($this->oField->GetLabel(), true)->AddHtml('</label>'); 78 } 79 $oOutput->AddHtml('</div>'); 80 81 // Value 82 $oOutput->AddHtml('<div class="form_field_control">'); 83 // - Help block 84 $oOutput->AddHtml('<div class="help-block"></div>'); 85 // - Value regarding the field type 86 switch($sFieldClass) 87 { 88 case 'Combodo\\iTop\\Form\\Field\\DateTimeField': 89 $oOutput->AddHtml('<div class="input-group date" id="datepicker_' . $this->oField->GetGlobalId() . '">'); 90 $oOutput->AddHtml('<input type="text" id="' . $this->oField->GetGlobalId() . '" name="' . $this->oField->GetId() . '" value="')->AddHtml($this->oField->GetDisplayValue(), true)->AddHtml('" class="form-control" maxlength="255" />'); 91 $oOutput->AddHtml('<span class="input-group-addon"><span class="glyphicon glyphicon-calendar"></span></span>'); 92 $oOutput->AddHtml('</div>'); 93 $sJSFormat = json_encode($this->oField->GetJSDateTimeFormat()); 94 $sLocale = Dict::S('Portal:Calendar-FirstDayOfWeek'); 95 $oOutput->AddJs( 96 <<<EOF 97 $('#datepicker_{$this->oField->GetGlobalId()}').datetimepicker({format: $sJSFormat, locale: '$sLocale'}); 98EOF 99 ); 100 break; 101 102 case 'Combodo\\iTop\\Form\\Field\\PasswordField': 103 $oOutput->AddHtml('<input type="password" id="' . $this->oField->GetGlobalId() . '" name="' . $this->oField->GetId() . '" value="')->AddHtml($this->oField->GetCurrentValue(), true)->AddHtml('" class="form-control" maxlength="255" autocomplete="off" />'); 104 break; 105 106 case 'Combodo\\iTop\\Form\\Field\\StringField': 107 case 'Combodo\\iTop\\Form\\Field\\UrlField': 108 case 'Combodo\\iTop\\Form\\Field\\EmailField': 109 case 'Combodo\\iTop\\Form\\Field\\PhoneField': 110 $oOutput->AddHtml('<input type="text" id="' . $this->oField->GetGlobalId() . '" name="' . $this->oField->GetId() . '" value="')->AddHtml($this->oField->GetCurrentValue(), true)->AddHtml('" class="form-control" maxlength="255" />'); 111 break; 112 113 case 'Combodo\\iTop\\Form\\Field\\SelectField': 114 case 'Combodo\\iTop\\Form\\Field\\MultipleSelectField': 115 $oOutput->AddHtml('<select id="' . $this->oField->GetGlobalId() . '" name="' . $this->oField->GetId() . '" ' . ( ($this->oField->GetMultipleValuesEnabled()) ? 'multiple' : '' ) . ' class="form-control">'); 116 foreach ($this->oField->GetChoices() as $sChoice => $sLabel) 117 { 118 // Note : The test is a double equal on purpose as the type of the value received from the XHR is not always the same as the type of the allowed values. (eg : string vs int) 119 $sSelectedAtt = ($this->oField->GetCurrentValue() == $sChoice) ? 'selected' : ''; 120 $oOutput->AddHtml('<option value="' . $sChoice . '" ' . $sSelectedAtt . ' >')->AddHtml($sLabel)->AddHtml('</option>'); 121 } 122 $oOutput->AddHtml('</select>'); 123 break; 124 } 125 $oOutput->AddHtml('</div>'); 126 127 // Closing container 128 $oOutput->AddHtml('</div>'); 129 break; 130 131 case 'Combodo\\iTop\\Form\\Field\\TextAreaField': 132 case 'Combodo\\iTop\\Form\\Field\\CaseLogField': 133 $bRichEditor = ($this->oField->GetFormat() === TextAreaField::ENUM_FORMAT_HTML); 134 135 // Opening container 136 $oOutput->AddHtml('<div class="form-group ' . $sFieldMandatoryClass . '">'); 137 138 // Label 139 $oOutput->AddHtml('<div class="form_field_label">'); 140 if ($this->oField->GetLabel() !== '') 141 { 142 $oOutput->AddHtml('<label for="' . $this->oField->GetGlobalId() . '" class="control-label">')->AddHtml($this->oField->GetLabel(), true)->AddHtml('</label>'); 143 } 144 $oOutput->AddHtml('</div>'); 145 146 // Value 147 $oOutput->AddHtml('<div class="form_field_control">'); 148 // - Help block 149 $oOutput->AddHtml('<div class="help-block"></div>'); 150 // First the edition area 151 $oOutput->AddHtml('<div>'); 152 $oOutput->AddHtml('<textarea id="' . $this->oField->GetGlobalId() . '" name="' . $this->oField->GetId() . '" class="form-control" rows="8">' . $this->oField->GetCurrentValue() . '</textarea>'); 153 $oOutput->AddHtml('</div>'); 154 // Then the previous entries if necessary 155 if ($sFieldClass === 'Combodo\\iTop\\Form\\Field\\CaseLogField') 156 { 157 $this->PreparingCaseLogEntries($oOutput); 158 } 159 $oOutput->AddHtml('</div>'); 160 161 // Closing container 162 $oOutput->AddHtml('</div>'); 163 164 // Some additional stuff if we are displaying it with a rich editor 165 if ($bRichEditor) 166 { 167 $sEditorLanguage = strtolower(trim(UserRights::GetUserLanguage())); 168 $oOutput->AddJs( 169<<<EOF 170 $('#{$this->oField->GetGlobalId()}').addClass('htmlEditor'); 171 $('#{$this->oField->GetGlobalId()}').ckeditor(function(){}, {language: '$sEditorLanguage', contentsLanguage: '$sEditorLanguage'}); 172EOF 173 ); 174 if (($this->oField->GetObject() !== null) && ($this->oField->GetTransactionId() !== null)) 175 { 176 $oOutput->AddJs(InlineImage::EnableCKEditorImageUpload($this->oField->GetObject(), utils::GetUploadTempId($this->oField->GetTransactionId()))); 177 } 178 } 179 break; 180 181 case 'Combodo\\iTop\\Form\\Field\\RadioField': 182 case 'Combodo\\iTop\\Form\\Field\\CheckboxField': 183 $sFieldType = ($sFieldClass === 'Combodo\\iTop\\Form\\Field\\RadioField') ? 'radio' : 'checkbox'; 184 185 // Opening container 186 $oOutput->AddHtml('<div class="form-group ' . $sFieldMandatoryClass . '" id="' . $this->oField->GetGlobalId() . '">'); 187 188 // Label 189 $oOutput->AddHtml('<div class="form_field_label">'); 190 if ($this->oField->GetLabel() !== '') 191 { 192 $oOutput->AddHtml('<div><label class="control-label">')->AddHtml($this->oField->GetLabel(), true)->AddHtml('</label></div>'); 193 } 194 $oOutput->AddHtml('</div>'); 195 196 // Value 197 $oOutput->AddHtml('<div class="form_field_control">'); 198 // - Help block 199 $oOutput->AddHtml('<div class="help-block"></div>'); 200 $oOutput->AddHtml('<div class="btn-group" data-toggle="buttons">'); 201 $i = 0; 202 foreach ($this->oField->GetChoices() as $sChoice => $sLabel) 203 { 204 // Note : The test is a double equal on purpose as the type of the value received from the XHR is not always the same as the type of the allowed values. (eg : string vs int) 205 $sCheckedAtt = ($this->oField->IsAmongValues($sChoice)) ? 'checked' : ''; 206 $sCheckedClass = ($this->oField->IsAmongValues($sChoice)) ? 'active' : ''; 207 $oOutput->AddHtml('<label class="btn btn-default ' . $sCheckedClass . '"><input type="' . $sFieldType . '" name="' . $this->oField->GetId() . '" id="' . $this->oField->GetId() . $i . '" value="' . $sChoice . '" ' . $sCheckedAtt . ' />' . $sLabel . '</label>'); 208 $i++; 209 } 210 $oOutput->AddHtml('</div>'); 211 $oOutput->AddHtml('</div>'); 212 213 // Closing container 214 $oOutput->AddHtml('</div>'); 215 break; 216 217 case 'Combodo\\iTop\\Form\\Field\\HiddenField': 218 $oOutput->AddHtml('<input type="hidden" id="' . $this->oField->GetGlobalId() . '" name="' . $this->oField->GetId() . '" value="')->AddHtml($this->oField->GetCurrentValue(), true)->AddHtml('"/>'); 219 break; 220 } 221 222 // JS FieldChange trigger (:input are not always at the same depth) 223 switch ($sFieldClass) 224 { 225 case 'Combodo\\iTop\\Form\\Field\\PasswordField': 226 case 'Combodo\\iTop\\Form\\Field\\StringField': 227 case 'Combodo\\iTop\\Form\\Field\\UrlField': 228 case 'Combodo\\iTop\\Form\\Field\\EmailField': 229 case 'Combodo\\iTop\\Form\\Field\\PhoneField': 230 case 'Combodo\\iTop\\Form\\Field\\TextAreaField': 231 case 'Combodo\\iTop\\Form\\Field\\CaseLogField': 232 case 'Combodo\\iTop\\Form\\Field\\SelectField': 233 case 'Combodo\\iTop\\Form\\Field\\MultipleSelectField': 234 case 'Combodo\\iTop\\Form\\Field\\HiddenField': 235 $oOutput->AddJs( 236 <<<EOF 237 $("#{$this->oField->GetGlobalId()}").off("change keyup").on("change keyup", function(){ 238 var me = this; 239 240 $(this).closest(".field_set").trigger("field_change", { 241 id: $(me).attr("id"), 242 name: $(me).closest(".form_field").attr("data-field-id"), 243 value: $(me).val() 244 }); 245 }); 246EOF 247 ); 248 break; 249 case 'Combodo\\iTop\\Form\\Field\\DateTimeField': 250 // We need the focusout event has the datepicker widget seems to override the change event 251 $oOutput->AddJs( 252 <<<EOF 253 $("#{$this->oField->GetGlobalId()}").off("change keyup focusout").on("change keyup focusout", function(){ 254 var me = this; 255 256 $(this).closest(".field_set").trigger("field_change", { 257 id: $(me).attr("id"), 258 name: $(me).closest(".form_field").attr("data-field-id"), 259 value: $(me).val() 260 }); 261 }); 262EOF 263 ); 264 break; 265 266 case 'Combodo\\iTop\\Form\\Field\\RadioField': 267 case 'Combodo\\iTop\\Form\\Field\\CheckboxField': 268 $oOutput->AddJs( 269 <<<EOF 270 $("#{$this->oField->GetGlobalId()} input").off("change").on("change", function(){ 271 var me = this; 272 273 $(this).closest(".field_set").trigger("field_change", { 274 id: $(me).closest("#{$this->oField->GetGlobalId()}").attr("id"), 275 name: $(me).attr("name"), 276 value: $(me).val() 277 }); 278 }); 279EOF 280 ); 281 break; 282 } 283 } 284 // ... and in read-only mode (or hidden) 285 else 286 { 287 // ... specific rendering for fields with multiple values 288 if (($this->oField instanceof MultipleChoicesField) && ($this->oField->GetMultipleValuesEnabled())) 289 { 290 // TODO 291 } 292 // ... classic rendering for fields with only one value 293 else 294 { 295 switch ($sFieldClass) 296 { 297 case 'Combodo\\iTop\\Form\\Field\\LabelField': 298 case 'Combodo\\iTop\\Form\\Field\\StringField': 299 case 'Combodo\\iTop\\Form\\Field\\UrlField': 300 case 'Combodo\\iTop\\Form\\Field\\EmailField': 301 case 'Combodo\\iTop\\Form\\Field\\PhoneField': 302 case 'Combodo\\iTop\\Form\\Field\\DateTimeField': 303 case 'Combodo\\iTop\\Form\\Field\\DurationField': 304 // Opening container 305 $oOutput->AddHtml('<div class="form-group form_group_small">'); 306 307 // Showing label / value only if read-only but not hidden 308 if (!$this->oField->GetHidden()) 309 { 310 // Label 311 $oOutput->AddHtml('<div class="form_field_label">'); 312 if ($this->oField->GetLabel() !== '') 313 { 314 $oOutput->AddHtml('<label for="' . $this->oField->GetGlobalId() . '" class="control-label">')->AddHtml($this->oField->GetLabel(), true)->AddHtml('</label>'); 315 } 316 $oOutput->AddHtml('</div>'); 317 318 // Value 319 $bEncodeHtmlEntities = ( in_array($sFieldClass, array('Combodo\\iTop\\Form\\Field\\UrlField', 'Combodo\\iTop\\Form\\Field\\EmailField', 'Combodo\\iTop\\Form\\Field\\PhoneField')) ) ? false : true; 320 $oOutput->AddHtml('<div class="form_field_control">'); 321 $oOutput->AddHtml('<div class="form-control-static">')->AddHtml($this->oField->GetDisplayValue(), $bEncodeHtmlEntities)->AddHtml('</div>'); 322 $oOutput->AddHtml('</div>'); 323 } 324 325 // Adding hidden input if not a label 326 if($sFieldClass !== 'Combodo\\iTop\\Form\\Field\\LabelField') 327 { 328 $sValueForInput = ($sFieldClass === 'Combodo\\iTop\\Form\\Field\\DateTimeField') ? $this->oField->GetDisplayValue() : $this->oField->GetCurrentValue(); 329 $oOutput->AddHtml('<input type="hidden" id="' . $this->oField->GetGlobalId() . '" name="' . $this->oField->GetId() . '" value="')->AddHtml($sValueForInput, true)->AddHtml('" class="form-control" />'); 330 } 331 332 // Closing container 333 $oOutput->AddHtml('</div>'); 334 break; 335 336 case 'Combodo\\iTop\\Form\\Field\\TextAreaField': 337 // Opening container 338 $oOutput->AddHtml('<div class="form-group">'); 339 340 // Showing label / value only if read-only but not hidden 341 if (!$this->oField->GetHidden()) 342 { 343 // Label 344 $oOutput->AddHtml('<div class="form_field_label">'); 345 if ($this->oField->GetLabel() !== '') 346 { 347 $oOutput->AddHtml('<label for="' . $this->oField->GetGlobalId() . '" class="control-label">')->AddHtml($this->oField->GetLabel(), true)->AddHtml('</label>'); 348 } 349 $oOutput->AddHtml('</div>'); 350 351 // Value 352 $oOutput->AddHtml('<div class="form_field_control">'); 353 $oOutput->AddHtml('<div class="form-control-static">')->AddHtml($this->oField->GetDisplayValue(), false)->AddHtml('</div>'); 354 $oOutput->AddHtml('</div>'); 355 } 356 357 // Adding hidden input 358 $oOutput->AddHtml('<input type="hidden" id="' . $this->oField->GetGlobalId() . '" name="' . $this->oField->GetId() . '" value="')->AddHtml($this->oField->GetCurrentValue(), true)->AddHtml('" class="form-control" />'); 359 360 // Closing container 361 $oOutput->AddHtml('</div>'); 362 break; 363 364 case 'Combodo\\iTop\\Form\\Field\\CaseLogField': 365 // Opening container 366 $oOutput->AddHtml('<div class="form-group ' . $sFieldMandatoryClass . '">'); 367 368 // Label 369 $oOutput->AddHtml('<div class="form_field_label">'); 370 if ($this->oField->GetLabel() !== '') 371 { 372 $oOutput->AddHtml('<label for="' . $this->oField->GetGlobalId() . '" class="control-label">')->AddHtml($this->oField->GetLabel(), true)->AddHtml('</label>'); 373 } 374 $oOutput->AddHtml('</div>'); 375 376 // Value 377 $oOutput->AddHtml('<div class="form_field_control">'); 378 // - Entries if necessary 379 $this->PreparingCaseLogEntries($oOutput); 380 $oOutput->AddHtml('</div>'); 381 382 // Closing container 383 $oOutput->AddHtml('</div>'); 384 break; 385 386 case 'Combodo\\iTop\\Form\\Field\\BlobField': 387 case 'Combodo\\iTop\\Form\\Field\\ImageField': 388 // Opening container 389 $oOutput->AddHtml('<div class="form-group">'); 390 391 // Showing label / value only if read-only but not hidden 392 if (!$this->oField->GetHidden()) 393 { 394 // Label 395 $oOutput->AddHtml('<div class="form_field_label">'); 396 if ($this->oField->GetLabel() !== '') 397 { 398 $oOutput->AddHtml('<label for="' . $this->oField->GetGlobalId() . '" class="control-label">')->AddHtml($this->oField->GetLabel(), true)->AddHtml('</label>'); 399 } 400 $oOutput->AddHtml('</div>'); 401 402 // Value 403 $oOutput->AddHtml('<div class="form_field_control">'); 404 $oOutput->AddHtml('<div class="form-control-static">'); 405 if($sFieldClass === 'Combodo\\iTop\\Form\\Field\\ImageField') 406 { 407 $oOutput->AddHtml('<img src="' . $this->oField->GetDisplayUrl() . '" />', false); 408 } 409 else 410 { 411 $oOutput->AddHtml($this->oField->GetDisplayValue(), false); 412 } 413 $oOutput->AddHtml('</div>'); 414 $oOutput->AddHtml('</div>'); 415 } 416 $oOutput->AddHtml('<input type="hidden" id="' . $this->oField->GetGlobalId() . '" name="' . $this->oField->GetId() . '" value="')->AddHtml($this->oField->GetCurrentValue(), true)->AddHtml('" class="form-control" />'); 417 418 // Closing container 419 $oOutput->AddHtml('</div>'); 420 break; 421 422 case 'Combodo\\iTop\\Form\\Field\\RadioField': 423 case 'Combodo\\iTop\\Form\\Field\\SelectField': 424 case 'Combodo\\iTop\\Form\\Field\\MultipleSelectField': 425 $aFieldChoices = $this->oField->GetChoices(); 426 $sFieldValue = (isset($aFieldChoices[$this->oField->GetCurrentValue()])) ? $aFieldChoices[$this->oField->GetCurrentValue()] : Dict::S('UI:UndefinedObject'); 427 428 // Opening container 429 $oOutput->AddHtml('<div class="form-group form_group_small">'); 430 431 // Showing label / value only if read-only but not hidden 432 if (!$this->oField->GetHidden()) 433 { 434 // Label 435 $oOutput->AddHtml('<div class="form_field_label">'); 436 if ($this->oField->GetLabel() !== '') 437 { 438 $oOutput->AddHtml('<label for="' . $this->oField->GetGlobalId() . '" class="control-label">')->AddHtml($this->oField->GetLabel(), true)->AddHtml('</label>'); 439 } 440 $oOutput->AddHtml('</div>'); 441 442 // Value 443 $oOutput->AddHtml('<div class="form_field_control">'); 444 $oOutput->AddHtml('<div class="form-control-static">' . $sFieldValue . '</div>'); 445 $oOutput->AddHtml('</div>'); 446 } 447 448 // Adding hidden value 449 $oOutput->AddHtml('<input type="hidden" id="' . $this->oField->GetGlobalId() . '" name="' . $this->oField->GetId() . '" value="' . $this->oField->GetCurrentValue() . '" class="form-control" />'); 450 451 // Closing container 452 $oOutput->AddHtml('</div>'); 453 break; 454 455 case 'Combodo\\iTop\\Form\\Field\\HiddenField': 456 $oOutput->AddHtml('<input type="hidden" id="' . $this->oField->GetGlobalId() . '" name="' . $this->oField->GetId() . '" value="')->AddHtml($this->oField->GetCurrentValue(), true)->AddHtml('"/>'); 457 break; 458 } 459 } 460 } 461 462 // Attaching JS widget only if field is hidden or NOT read only 463 if($this->oField->GetHidden() || !$this->oField->GetReadOnly()) 464 { 465 466 // JS Form field widget construct 467 $aValidators = array(); 468 foreach ($this->oField->GetValidators() as $oValidator) 469 { 470 $aValidators[$oValidator::GetName()] = array( 471 'reg_exp' => $oValidator->GetRegExp(), 472 'message' => Dict::S($oValidator->GetErrorMessage()) 473 ); 474 } 475 476 $sFormFieldOptions = json_encode(array( 477 'validators' => $aValidators 478 )); 479 480 switch ($sFieldClass) 481 { 482 case 'Combodo\\iTop\\Form\\Field\\PasswordField': 483 case 'Combodo\\iTop\\Form\\Field\\StringField': 484 case 'Combodo\\iTop\\Form\\Field\\UrlField': 485 case 'Combodo\\iTop\\Form\\Field\\EmailField': 486 case 'Combodo\\iTop\\Form\\Field\\PhoneField': 487 case 'Combodo\\iTop\\Form\\Field\\SelectField': 488 case 'Combodo\\iTop\\Form\\Field\\MultipleSelectField': 489 case 'Combodo\\iTop\\Form\\Field\\HiddenField': 490 case 'Combodo\\iTop\\Form\\Field\\RadioField': 491 case 'Combodo\\iTop\\Form\\Field\\CheckboxField': 492 case 'Combodo\\iTop\\Form\\Field\\DateTimeField': 493 $oOutput->AddJs( 494 <<<EOF 495 $("[data-field-id='{$this->oField->GetId()}'][data-form-path='{$this->oField->GetFormPath()}']").portal_form_field($sFormFieldOptions); 496EOF 497 ); 498 break; 499 case 'Combodo\\iTop\\Form\\Field\\TextAreaField': 500 case 'Combodo\\iTop\\Form\\Field\\CaseLogField': 501 $bRichEditor = ($this->oField->GetFormat() === TextAreaField::ENUM_FORMAT_HTML); 502 if($bRichEditor) 503 { 504 // Overloading $sFormFieldOptions to include the set_current_value_callback. It would have been nicer to refactor the variable for all field types, but as this is a fix for a maintenance release, we rather be safe. 505 $sValidators = json_encode($aValidators); 506 $oOutput->AddJs( 507 <<<EOF 508 $("[data-field-id='{$this->oField->GetId()}'][data-form-path='{$this->oField->GetFormPath()}']").portal_form_field_html({ 509 validators: $sValidators, 510 set_current_value_callback: function(me, oEvent, oData){ $(me.element).find('textarea').val(oData); } 511 }); 512EOF 513 ); 514 } 515 else 516 { 517 $oOutput->AddJs( 518 <<<EOF 519 $("[data-field-id='{$this->oField->GetId()}'][data-form-path='{$this->oField->GetFormPath()}']").portal_form_field($sFormFieldOptions); 520EOF 521 ); 522 } 523 break; 524 } 525 } 526 527 // Finally, no matter the field mode 528 switch ($sFieldClass) 529 { 530 case 'Combodo\\iTop\\Form\\Field\\TextAreaField': 531 case 'Combodo\\iTop\\Form\\Field\\CaseLogField': 532 $bRichEditor = ($this->oField->GetFormat() === TextAreaField::ENUM_FORMAT_HTML); 533 if($bRichEditor) 534 { 535 // MagnificPopup on images 536 $oOutput->AddJs(InlineImage::FixImagesWidth()); 537 } 538 break; 539 } 540 541 return $oOutput; 542 } 543 544 /** 545 * @param RenderingOutput $oOutput 546 * 547 * @throws \Exception 548 */ 549 protected function PreparingCaseLogEntries(RenderingOutput &$oOutput) 550 { 551 $aEntries = $this->oField->GetEntries(); 552 if (count($aEntries) > 0) 553 { 554 $oOutput->AddHtml('<div>'); 555 for ($i = 0; $i < count($aEntries); $i++) 556 { 557 $sEntryDate = AttributeDateTime::GetFormat()->Format($aEntries[$i]['date']); 558 $sEntryUser = $aEntries[$i]['user_login']; 559 $sEntryHeader = Dict::Format('UI:CaseLog:Header_Date_UserName', $sEntryDate, $sEntryUser); 560 561 // Only the last 2 entries are expanded by default 562 $sEntryContentExpanded = ($i < 2) ? 'true' : 'false'; 563 $sEntryHeaderButtonClass = ($i < 2) ? '' : 'collapsed'; 564 $sEntryContentClass = ($i < 2) ? 'in' : ''; 565 $sEntryContentId = 'caselog_field_entry_content-' . $this->oField->GetGlobalId() . '-' . $i; 566 $sEntryHtml = AttributeText::RenderWikiHtml($aEntries[$i]['message_html'], true /* wiki only */); 567 $sEntryHtml = InlineImage::FixUrls($sEntryHtml); 568 569 // Note : We use CKEditor stylesheet to format this 570 $oOutput->AddHtml( 571<<<EOF 572 <div class="caselog_field_entry cke_inner"> 573 <div class="caselog_field_entry_header"> 574 {$sEntryHeader} 575 <div class="pull-right"> 576 <span class="caselog_field_entry_button {$sEntryHeaderButtonClass}" data-toggle="collapse" href="#{$sEntryContentId}" aria-expanded="{$sEntryContentExpanded}" aria-controls="{$sEntryContentId}"></span> 577 </div> 578 </div> 579 <div class="caselog_field_entry_content collapse {$sEntryContentClass}" id="{$sEntryContentId}"> 580 {$sEntryHtml} 581 </div> 582 </div> 583EOF 584 ); 585 } 586 $oOutput->AddHtml('</div>'); 587 } 588 } 589 590} 591