*/ class BsSimpleFieldRenderer extends BsFieldRenderer { /** * @inheritDoc */ public function Render() { $oOutput = parent::Render(); $sFieldClass = get_class($this->oField); $sFieldMandatoryClass = ($this->oField->GetMandatory()) ? 'form_mandatory' : ''; $sFieldDescriptionForHTMLTag = ($this->oField->HasDescription()) ? 'data-tooltip-content="'.utils::HtmlEntities($this->oField->GetDescription()).'"' : ''; // Rendering field in edition mode if (!$this->oField->GetReadOnly() && !$this->oField->GetHidden()) { // HTML content switch ($sFieldClass) { case 'Combodo\\iTop\\Form\\Field\\DateTimeField': case 'Combodo\\iTop\\Form\\Field\\PasswordField': 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 $oOutput->AddHtml('
'); // Label $oOutput->AddHtml('
'); if ($this->oField->GetLabel() !== '') { $oOutput->AddHtml(''); } $oOutput->AddHtml('
'); // Value $oOutput->AddHtml('
'); // - Help block $oOutput->AddHtml('
'); // - Value regarding the field type switch($sFieldClass) { case 'Combodo\\iTop\\Form\\Field\\DateTimeField': $oOutput->AddHtml('
'); $oOutput->AddHtml(''); $oOutput->AddHtml(''); $oOutput->AddHtml('
'); $sJSFormat = json_encode($this->oField->GetJSDateTimeFormat()); $sLocale = Dict::S('Portal:Calendar-FirstDayOfWeek'); $oOutput->AddJs( <<oField->GetGlobalId()}').datetimepicker({format: $sJSFormat, locale: '$sLocale'}); EOF ); break; case 'Combodo\\iTop\\Form\\Field\\PasswordField': $oOutput->AddHtml(''); break; 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; case 'Combodo\\iTop\\Form\\Field\\SelectField': case 'Combodo\\iTop\\Form\\Field\\MultipleSelectField': $oOutput->AddHtml(''); break; } $oOutput->AddHtml('
'); // Closing container $oOutput->AddHtml('
'); break; case 'Combodo\\iTop\\Form\\Field\\TextAreaField': case 'Combodo\\iTop\\Form\\Field\\CaseLogField': $bRichEditor = ($this->oField->GetFormat() === TextAreaField::ENUM_FORMAT_HTML); // Opening container $oOutput->AddHtml('
'); // Label $oOutput->AddHtml('
'); if ($this->oField->GetLabel() !== '') { $oOutput->AddHtml(''); } $oOutput->AddHtml('
'); // Value $oOutput->AddHtml('
'); // - Help block $oOutput->AddHtml('
'); // First the edition area $oOutput->AddHtml('
'); $oOutput->AddHtml(''); $oOutput->AddHtml('
'); // Then the previous entries if necessary if ($sFieldClass === 'Combodo\\iTop\\Form\\Field\\CaseLogField') { $this->PreparingCaseLogEntries($oOutput); } $oOutput->AddHtml('
'); // Closing container $oOutput->AddHtml('
'); // Some additional stuff if we are displaying it with a rich editor if ($bRichEditor) { $aConfig = utils::GetCkeditorPref(); $aConfig['extraPlugins'] = 'codesnippet'; $sJsConfig = json_encode($aConfig); $oOutput->AddJs( <<oField->GetGlobalId()}').addClass('htmlEditor'); $('#{$this->oField->GetGlobalId()}').ckeditor(function(){}, $sJsConfig).editor.on("change", function(){ $('#{$this->oField->GetGlobalId()}').trigger("change"); }); EOF ); if (($this->oField->GetObject() !== null) && ($this->oField->GetTransactionId() !== null)) { $oOutput->AddJs(InlineImage::EnableCKEditorImageUpload($this->oField->GetObject(), utils::GetUploadTempId($this->oField->GetTransactionId()))); } } break; case 'Combodo\\iTop\\Form\\Field\\RadioField': case 'Combodo\\iTop\\Form\\Field\\CheckboxField': $sFieldType = ($sFieldClass === 'Combodo\\iTop\\Form\\Field\\RadioField') ? 'radio' : 'checkbox'; // Opening container $oOutput->AddHtml('
'); // Label $oOutput->AddHtml('
'); if ($this->oField->GetLabel() !== '') { $oOutput->AddHtml('
'); } $oOutput->AddHtml('
'); // Value $oOutput->AddHtml('
'); // - Help block $oOutput->AddHtml('
'); $oOutput->AddHtml('
'); $i = 0; foreach ($this->oField->GetChoices() as $sChoice => $sLabel) { // 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) $sCheckedAtt = ($this->oField->IsAmongValues($sChoice)) ? 'checked' : ''; $sCheckedClass = ($this->oField->IsAmongValues($sChoice)) ? 'active' : ''; $oOutput->AddHtml(''); $i++; } $oOutput->AddHtml('
'); $oOutput->AddHtml('
'); // Closing container $oOutput->AddHtml('
'); break; case 'Combodo\\iTop\\Form\\Field\\HiddenField': $oOutput->AddHtml(''); break; } // JS FieldChange trigger (:input are not always at the same depth) switch ($sFieldClass) { case 'Combodo\\iTop\\Form\\Field\\PasswordField': 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': case 'Combodo\\iTop\\Form\\Field\\MultipleSelectField': case 'Combodo\\iTop\\Form\\Field\\HiddenField': $oOutput->AddJs( <<oField->GetGlobalId()}").off("change keyup").on("change keyup", function(){ var me = this; $(this).closest(".field_set").trigger("field_change", { id: $(me).attr("id"), name: $(me).closest(".form_field").attr("data-field-id"), value: $(me).val() }); }).on("mouseup", function(){this.focus();}); EOF ); break; case 'Combodo\\iTop\\Form\\Field\\DateTimeField': // We need the focusout event has the datepicker widget seems to override the change event $oOutput->AddJs( <<oField->GetGlobalId()}").off("change keyup focusout").on("change keyup focusout", function(){ var me = this; $(this).closest(".field_set").trigger("field_change", { id: $(me).attr("id"), name: $(me).closest(".form_field").attr("data-field-id"), value: $(me).val() }); }); EOF ); break; case 'Combodo\\iTop\\Form\\Field\\RadioField': case 'Combodo\\iTop\\Form\\Field\\CheckboxField': $oOutput->AddJs( <<oField->GetGlobalId()} input").off("change").on("change", function(){ var me = this; $(this).closest(".field_set").trigger("field_change", { id: $(me).closest("#{$this->oField->GetGlobalId()}").attr("id"), name: $(me).attr("name"), value: $(me).val() }); }); EOF ); break; } } // ... and in read-only mode (or hidden) else { // ... specific rendering for fields with multiple values if (($this->oField instanceof MultipleChoicesField) && ($this->oField->GetMultipleValuesEnabled())) { // TODO } // ... classic rendering for fields with only one value else { switch ($sFieldClass) { case 'Combodo\\iTop\\Form\\Field\\LabelField': 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 $oOutput->AddHtml('
'); // Showing label / value only if read-only but not hidden if (!$this->oField->GetHidden()) { // Label $oOutput->AddHtml('
'); if ($this->oField->GetLabel() !== '') { $oOutput->AddHtml(''); } $oOutput->AddHtml('
'); // Value $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('
'); } // Adding hidden input if not a label if($sFieldClass !== 'Combodo\\iTop\\Form\\Field\\LabelField') { $sValueForInput = ($sFieldClass === 'Combodo\\iTop\\Form\\Field\\DateTimeField') ? $this->oField->GetDisplayValue() : $this->oField->GetCurrentValue(); $oOutput->AddHtml(''); } // Closing container $oOutput->AddHtml('
'); break; case 'Combodo\\iTop\\Form\\Field\\TextAreaField': // Opening container $oOutput->AddHtml('
'); // Showing label / value only if read-only but not hidden if (!$this->oField->GetHidden()) { // Label $oOutput->AddHtml('
'); if ($this->oField->GetLabel() !== '') { $oOutput->AddHtml(''); } $oOutput->AddHtml('
'); // Value $oOutput->AddHtml('
'); $oOutput->AddHtml('
')->AddHtml($this->oField->GetDisplayValue(), false)->AddHtml('
'); $oOutput->AddHtml('
'); } // Adding hidden input $oOutput->AddHtml(''); // Closing container $oOutput->AddHtml('
'); break; case 'Combodo\\iTop\\Form\\Field\\CaseLogField': // Opening container $oOutput->AddHtml('
'); // Label $oOutput->AddHtml('
'); if ($this->oField->GetLabel() !== '') { $oOutput->AddHtml(''); } $oOutput->AddHtml('
'); // Value $oOutput->AddHtml('
'); // - Entries if necessary $this->PreparingCaseLogEntries($oOutput); $oOutput->AddHtml('
'); // Closing container $oOutput->AddHtml('
'); break; case 'Combodo\\iTop\\Form\\Field\\BlobField': case 'Combodo\\iTop\\Form\\Field\\ImageField': // Opening container $oOutput->AddHtml('
'); // Showing label / value only if read-only but not hidden if (!$this->oField->GetHidden()) { // Label $oOutput->AddHtml('
'); if ($this->oField->GetLabel() !== '') { $oOutput->AddHtml(''); } $oOutput->AddHtml('
'); // Value $oOutput->AddHtml('
'); $oOutput->AddHtml('
'); if($sFieldClass === 'Combodo\\iTop\\Form\\Field\\ImageField') { $oOutput->AddHtml('', false); } else { $oOutput->AddHtml($this->oField->GetDisplayValue(), false); } $oOutput->AddHtml('
'); $oOutput->AddHtml('
'); } $oOutput->AddHtml(''); // Closing container $oOutput->AddHtml('
'); break; case 'Combodo\\iTop\\Form\\Field\\RadioField': case 'Combodo\\iTop\\Form\\Field\\SelectField': case 'Combodo\\iTop\\Form\\Field\\MultipleSelectField': $aFieldChoices = $this->oField->GetChoices(); $sFieldValue = (isset($aFieldChoices[$this->oField->GetCurrentValue()])) ? $aFieldChoices[$this->oField->GetCurrentValue()] : Dict::S('UI:UndefinedObject'); // Opening container $oOutput->AddHtml('
'); // Showing label / value only if read-only but not hidden if (!$this->oField->GetHidden()) { // Label $oOutput->AddHtml('
'); if ($this->oField->GetLabel() !== '') { $oOutput->AddHtml(''); } $oOutput->AddHtml('
'); // Value $oOutput->AddHtml('
'); $oOutput->AddHtml('
' . $sFieldValue . '
'); $oOutput->AddHtml('
'); } // Adding hidden value $oOutput->AddHtml(''); // Closing container $oOutput->AddHtml('
'); break; case 'Combodo\\iTop\\Form\\Field\\HiddenField': $oOutput->AddHtml(''); break; } } } // Attaching JS widget only if field is hidden or NOT read only if($this->oField->GetHidden() || !$this->oField->GetReadOnly()) { // JS Form field widget construct $aValidators = array(); foreach ($this->oField->GetValidators() as $oValidator) { $aValidators[$oValidator::GetName()] = array( 'reg_exp' => $oValidator->GetRegExp(), 'message' => Dict::S($oValidator->GetErrorMessage()) ); } $sFormFieldOptions = json_encode(array( 'validators' => $aValidators )); switch ($sFieldClass) { case 'Combodo\\iTop\\Form\\Field\\PasswordField': 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': case 'Combodo\\iTop\\Form\\Field\\RadioField': case 'Combodo\\iTop\\Form\\Field\\CheckboxField': case 'Combodo\\iTop\\Form\\Field\\DateTimeField': $oOutput->AddJs( <<oField->GetFormat() === TextAreaField::ENUM_FORMAT_HTML); if($bRichEditor) { // 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. $sValidators = json_encode($aValidators); $oOutput->AddJs( <<AddJs( <<oField->GetFormat() === TextAreaField::ENUM_FORMAT_HTML); if($bRichEditor) { // MagnificPopup on images $oOutput->AddJs(InlineImage::FixImagesWidth()); // Trigger highlighter for all code blocks in this caselog $oOutput->AddJs(<<oField->GetEntries(); $iNbEntries = count($aEntries); if ($iNbEntries > 0) { // Dict entries $sOpenAllEntriesTooltip = utils::HtmlEntities(Dict::S('UI:Layout:ActivityPanel:Tab:Toolbar:Action:OpenAll:Tooltip')); $sCloseAllEntriesTooltip = utils::HtmlEntities(Dict::S('UI:Layout:ActivityPanel:Tab:Toolbar:Action:CloseAll:Tooltip')); $sUsersCountTooltip = utils::HtmlEntities(Dict::S('UI:Layout:ActivityPanel:Tab:Toolbar:Info:AuthorsCount:Tooltip')); $sEntriesCountTooltip = utils::HtmlEntities(Dict::S('UI:Layout:ActivityPanel:Tab:Toolbar:Info:MessagesCount:Tooltip')); $sCloseEntryTooltip = utils::HtmlEntities(Dict::S('Portal:Form:Caselog:Entry:Close:Tooltip')); // First pass to retrieve number of users $aUserIds = array(); for ($i = 0; $i < $iNbEntries; $i++) { $iEntryUserId = $aEntries[$i]['user_id']; if (!in_array($iEntryUserId, $aUserIds)) { $aUserIds[] = $iEntryUserId; } } $iNbUsers = count($aUserIds); // Opening thread $oOutput->AddHtml(<< HTML ); // - Header $oOutput->AddHtml(<< {$iNbUsers} {$iNbEntries} HTML ); // - Content $oOutput->AddHtml(<< HTML ); $sThreadUniqueId = uniqid(); $sLastDate = null; $sLastUserId = null; $iLastLoopIndex = $iNbEntries - 1; // Caching profile picture url as it is resource consuming $aContactPicturesCache = array(); $aPeerColorClassCache = array(); // Current user $iCurrentUserId = UserRights::GetUserId(); for ($i = 0; $i < $iNbEntries; $i++) { $sEntryDatetime = AttributeDateTime::GetFormat()->Format($aEntries[$i]['date']); $sEntryDate = AttributeDate::GetFormat()->Format($aEntries[$i]['date']); $sEntryUserLogin = $aEntries[$i]['user_login']; $iEntryUserId = $aEntries[$i]['user_id']; // Retrieve (and cache) profile picture if available (standard datamodel) if (!array_key_exists($iEntryUserId, $aContactPicturesCache)) { $oEntryUser = MetaModel::GetObject('User', $iEntryUserId, false, true); if(is_null($oEntryUser)) { $sEntryContactPictureAbsoluteUrl = null; } else { $sEntryContactPictureAbsoluteUrl = UserRights::GetUserPictureAbsUrl($oEntryUser->Get('login'), false); } $aContactPicturesCache[$iEntryUserId] = $sEntryContactPictureAbsoluteUrl; } // Open user block if previous user was different or if previous date was different if (($iEntryUserId !== $sLastUserId) || ($sEntryDate !== $sLastDate)) { if ($sEntryDate !== $sLastDate) { $oOutput->AddHtml(<<{$sEntryDate} HTML ); } // Open block if ($iEntryUserId === $iCurrentUserId) { $sEntryBlockClass = 'caselog-thread--block-me'; } else { if (!array_key_exists($iEntryUserId, $aPeerColorClassCache)) { $iPeerClassNumber = (count($aPeerColorClassCache) % 5) + 1; $aPeerColorClassCache[$iEntryUserId] = 'caselog-thread--block-color-'.$iPeerClassNumber; } $sEntryBlockClass = $aPeerColorClassCache[$iEntryUserId]; } $oOutput->AddHtml(<< HTML ); // Open medallion from profile picture or first name letter $sEntryMedallionStyle = (empty($aContactPicturesCache[$iEntryUserId]) === false) ? ' background-image: url(\''.$aContactPicturesCache[$iEntryUserId].'\');' : ''; $sEntryMedallionContent = (empty($aContactPicturesCache[$iEntryUserId]) === false) ? '' : UserRights::GetUserInitials($sEntryUserLogin); // - Entry tooltip $sEntryMedallionTooltip = utils::HtmlEntities($sEntryUserLogin); $sEntryMedallionTooltipPlacement = ($iEntryUserId === $iCurrentUserId) ? 'left' : 'right'; $oOutput->AddHtml(<< $sEntryMedallionContent
{$sEntryUserLogin}
HTML ); // Open entries $oOutput->AddHtml(<< HTML ); } // Prepare entry content $sEntryId = 'caselog-thread--block-entry-'.$sThreadUniqueId.'-'.$i; $sEntryHtml = AttributeText::RenderWikiHtml($aEntries[$i]['message_html'], true /* wiki only */); $sEntryHtml = InlineImage::FixUrls($sEntryHtml); // Add entry $oOutput->AddHtml(<<
{$sEntryHtml}
HTML ); // Close user block if next user is different or if last entry or if next entry is for another date if (($i === $iLastLoopIndex) || ($i < $iLastLoopIndex && $iEntryUserId !== $aEntries[$i + 1]['user_id']) || ($i < $iLastLoopIndex && $sEntryDate !== AttributeDate::GetFormat()->Format($aEntries[$i + 1]['date']))) { // Close entries and block $oOutput->AddHtml(<< HTML ); } // Update current loop informations $sLastDate = $sEntryDate; $sLastUserId = $iEntryUserId; } // Close thread content and thread $oOutput->AddHtml(<< HTML ); // Add JS handlers $oOutput->AddJs(<<