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