/** * Helper class to build interactive forms to be used either in stand-alone * modal dialog or in "property-sheet" panes. * * @copyright Copyright (C) 2010-2012 Combodo SARL * @license http://opensource.org/licenses/AGPL-3.0 */ class DesignerForm { protected $aFieldSets; protected $sCurrentFieldSet; protected $sScript; protected $sReadyScript; protected $sFormId; protected $sFormPrefix; protected $sParamsContainer; protected $oParentForm; protected $aSubmitParams; protected $sSubmitTo; protected $bReadOnly; public function __construct() { $this->aFieldSets = array(); $this->sCurrentFieldSet = ''; $this->sScript = ''; $this->sReadyScript = ''; $this->sFormPrefix = ''; $this->sParamsContainer = ''; $this->sFormId = 'form_'.rand(); $this->oParentForm = null; $this->bReadOnly = false; $this->StartFieldSet($this->sCurrentFieldSet); } public function AddField(DesignerFormField $oField) { if (!is_array($this->aFieldSets[$this->sCurrentFieldSet])) { $this->aFieldSets[$this->sCurrentFieldSet] = array(); } $this->aFieldSets[$this->sCurrentFieldSet][] = $oField; $oField->SetForm($this); } public function StartFieldSet($sLabel) { $this->sCurrentFieldSet = $sLabel; if (!array_key_exists($this->sCurrentFieldSet, $this->aFieldSets)) { $this->aFieldSets[$this->sCurrentFieldSet] = array(); } } public function Render($oP, $bReturnHTML = false) { $sReturn = ''; if ($this->oParentForm == null) { $sFormId = $this->sFormId; $sReturn = '
'; } else { $sFormId = $this->oParentForm->sFormId; } $sHiddenFields = ''; foreach($this->aFieldSets as $sLabel => $aFields) { $aDetails = array(); if ($sLabel != '') { $sReturn .= '
'; $sReturn .= ''.$sLabel.''; } foreach($aFields as $oField) { $aRow = $oField->Render($oP, $sFormId); if ($oField->IsVisible()) { $sValidation = ' '.$this->GetValidationArea($oField->GetCode()).''; $sField = $aRow['value'].$sValidation; $aDetails[] = array('label' => $aRow['label'], 'value' => $sField); } else { $sHiddenFields .= $aRow['value']; } } $sReturn .= $oP->GetDetails($aDetails); if ($sLabel != '') { $sReturn .= '
'; } } $sReturn .= $sHiddenFields; if ($this->oParentForm == null) { $sReturn .= '
'; } if($this->sScript != '') { $oP->add_script($this->sScript); } if($this->sReadyScript != '') { $oP->add_ready_script($this->sReadyScript); } if ($bReturnHTML) { return $sReturn; } else { $oP->add($sReturn); } } public function SetSubmitParams($sSubmitToUrl, $aSubmitParams) { $this->sSubmitTo = $sSubmitToUrl; $this->aSubmitParams = $aSubmitParams; } public function CopySubmitParams($oParentForm) { $this->sSubmitTo = $oParentForm->sSubmitTo; $this->aSubmitParams = $oParentForm->aSubmitParams; } public function RenderAsPropertySheet($oP, $bReturnHTML = false, $sNotifyParentSelector = null) { $sReturn = ''; $sActionUrl = addslashes($this->sSubmitTo); $sJSSubmitParams = json_encode($this->aSubmitParams); if ($this->oParentForm == null) { $sFormId = $this->sFormId; $sReturn = '
'; $sReturn .= ''; $sReturn .= ''; } else { $sFormId = $this->oParentForm->sFormId; } $sHiddenFields = ''; foreach($this->aFieldSets as $sLabel => $aFields) { $aDetails = array(); if ($sLabel != '') { $sReturn .= ''; } foreach($aFields as $oField) { $aRow = $oField->Render($oP, $sFormId, 'property'); if ($oField->IsVisible()) { $sFieldId = $this->GetFieldId($oField->GetCode()); $sValidation = $this->GetValidationArea($oField->GetCode(), ''); $sValidationFields = ''; $sReturn .= ''; $sReturn .= '
'.Dict::S('UI:Form:Property').''.Dict::S('UI:Form:Value').' 
'.$sLabel.'
'.$sValidation.'
'.$aRow['label'].''.$aRow['value']; if (!($oField instanceof DesignerFormSelectorField)) { $sReturn .= $sValidationFields; } $sNotifyParentSelectorJS = is_null($sNotifyParentSelector) ? 'null' : "'".addslashes($sNotifyParentSelector)."'"; $sAutoApply = $oField->IsAutoApply() ? 'true' : 'false'; $this->AddReadyScript( <<oParentForm == null) { $sFormId = $this->sFormId; $sReturn .= '
'; $sReturn .= $sHiddenFields; $sReturn .= '
'; $sReturn .= '
'; // for the return of the submit operation } else { $sReturn .= $sHiddenFields; } $this->AddReadyScript( <<sScript != '') { $oP->add_script($this->sScript); } if($this->sReadyScript != '') { $oP->add_ready_script($this->sReadyScript); } if ($bReturnHTML) { return $sReturn; } else { $oP->add($sReturn); } } public function RenderAsDialog($oPage, $sDialogId, $sDialogTitle, $iDialogWidth, $sOkButtonLabel) { $sDialogTitle = addslashes($sDialogTitle); $sOkButtonLabel = addslashes($sOkButtonLabel); $sCancelButtonLabel = 'Cancel'; //TODO: localize $oPage->add("
"); $this->Render($oPage); $oPage->add('
'); $oPage->add_ready_script( <<aFieldSets as $sLabel => $aFields) { foreach($aFields as $oField) { $oField->ReadParam($aValues); } } return $aValues; } public function SetPrefix($sPrefix) { $this->sFormPrefix = $sPrefix; } public function GetPrefix() { return $this->sFormPrefix; } public function SetReadOnly($bReadOnly = true) { $this->bReadOnly = $bReadOnly; } public function IsReadOnly() { if ($this->oParentForm == null) { return $this->bReadOnly; } else { return $this->oParentForm->IsReadOnly(); } } public function SetParamsContainer($sParamsContainer) { $this->sParamsContainer = $sParamsContainer; } public function GetParamsContainer() { if ($this->oParentForm == null) { return $this->sParamsContainer; } else { return $this->oParentForm->GetParamsContainer(); } } public function SetParentForm($oParentForm) { $this->oParentForm = $oParentForm; } public function AddScript($sScript) { $this->sScript .= $sScript; } public function AddReadyScript($sScript) { $this->sReadyScript .= $sScript; } public function GetFieldId($sCode) { return $this->sFormPrefix.'attr_'.$sCode; } public function GetFieldName($sCode) { return 'attr_'.$sCode; } public function GetParamName($sCode) { return 'attr_'.$sCode; } public function GetValidationArea($sCode, $sContent = '') { return "sFormPrefix}attr_$sCode\">$sContent"; } public function GetAsyncActionClass() { return $this->sAsyncActionClass; } } class DesignerTabularForm extends DesignerForm { protected $aTable; public function __construct() { parent::__construct(); $this->aTable = array(); } public function AddRow($aRow) { $this->aTable[] = $aRow; } public function Render($oP, $bReturnHTML = false) { $sReturn = ''; if ($this->oParentForm == null) { $sFormId = $this->sFormId; $sReturn = '
'; } else { $sFormId = $this->oParentForm->sFormId; } $sHiddenFields = ''; $sReturn .= ''; foreach($this->aTable as $aRow) { $sReturn .= ''; foreach($aRow as $field) { if (!is_object($field)) { // Shortcut: pass a string for a cell containing just a label $sReturn .= ''; } else { $field->SetForm($this); $aFieldData = $field->Render($oP, $sFormId); if ($field->IsVisible()) { // put the label and value separated by a non-breaking space if needed $aData = array(); foreach(array('label', 'value') as $sCode ) { if ($aFieldData[$sCode] != '') { $aData[] = $aFieldData[$sCode]; } } $sReturn .= ''; } else { $sHiddenFields .= $aRow['value']; } } } $sReturn .= ''; } $sReturn .= '
'.$field.''.implode(' ', $aData).'
'; $sReturn .= $sHiddenFields; if($this->sScript != '') { $oP->add_script($this->sScript); } if($this->sReadyScript != '') { $oP->add_ready_script($this->sReadyScript); } if ($bReturnHTML) { return $sReturn; } else { $oP->add($sReturn); } } public function ReadParams(&$aValues = array()) { foreach($this->aTable as $aRow) { foreach($aRow as $field) { if (is_object($field)) { $field->SetForm($this); $field->ReadParam($aValues); } } } return $aValues; } } class DesignerFormField { protected $sLabel; protected $sCode; protected $defaultValue; protected $oForm; protected $bMandatory; protected $bReadOnly; protected $bAutoApply; public function __construct($sCode, $sLabel, $defaultValue) { $this->sLabel = $sLabel; $this->sCode = $sCode; $this->defaultValue = $defaultValue; $this->bMandatory = false; $this->bReadOnly = false; $this->bAutoApply = false; } public function GetCode() { return $this->sCode; } public function SetForm($oForm) { $this->oForm = $oForm; } public function SetMandatory($bMandatory = true) { $this->bMandatory = $bMandatory; } public function SetReadOnly($bReadOnly = true) { $this->bReadOnly = $bReadOnly; } public function IsReadOnly() { return ($this->oForm->IsReadOnly() || $this->bReadOnly); } public function SetAutoApply($bAutoApply) { $this->bAutoApply = $bAutoApply; } public function IsAutoApply() { return $this->bAutoApply; } public function Render(WebPage $oP, $sFormId, $sRenderMode='dialog') { $sId = $this->oForm->GetFieldId($this->sCode); $sName = $this->oForm->GetFieldName($this->sCode); return array('label' => $this->sLabel, 'value' => "defaultValue, ENT_QUOTES, 'UTF-8')."\">"); } public function ReadParam(&$aValues) { if ($this->IsReadOnly()) { $aValues[$this->sCode] = $this->defaultValue; } else { if ($this->oForm->GetParamsContainer() != '') { $aParams = utils::ReadParam($this->oForm->GetParamsContainer(), array(), false, 'raw_data'); if (array_key_exists($this->oForm->GetParamName($this->sCode), $aParams)) { $aValues[$this->sCode] = $aParams[$this->oForm->GetParamName($this->sCode)]; } else { $aValues[$this->sCode] = $this->defaultValue; } } else { $aValues[$this->sCode] = utils::ReadParam($this->oForm->GetParamName($this->sCode), $this->defaultValue, false, 'raw_data'); } } } public function IsVisible() { return true; } } class DesignerLabelField extends DesignerFormField { protected $sDescription; public function __construct($sLabel, $sDescription) { parent::__construct('', $sLabel, ''); $this->sDescription = $sDescription; } public function Render(WebPage $oP, $sFormId, $sRenderMode='dialog') { $sId = $this->oForm->GetFieldId($this->sCode); $sName = $this->oForm->GetFieldName($this->sCode); return array('label' => $this->sLabel, 'value' => $sDescription); } public function ReadParam(&$aValues) { } public function IsVisible() { return true; } } class DesignerTextField extends DesignerFormField { protected $sValidationPattern; public function __construct($sCode, $sLabel = '', $defaultValue = '') { parent::__construct($sCode, $sLabel, $defaultValue); $this->sValidationPattern = ''; } public function SetValidationPattern($sValidationPattern) { $this->sValidationPattern = $sValidationPattern; } public function Render(WebPage $oP, $sFormId, $sRenderMode='dialog') { $sId = $this->oForm->GetFieldId($this->sCode); $sName = $this->oForm->GetFieldName($this->sCode); $sPattern = addslashes($this->sValidationPattern); $sMandatory = $this->bMandatory ? 'true' : 'false'; $sReadOnly = $this->IsReadOnly() ? 'readonly' : ''; $oP->add_ready_script( << $this->sLabel, 'value' => "defaultValue, ENT_QUOTES, 'UTF-8')."\">"); } public function ReadParam(&$aValues) { parent::ReadParam($aValues); if (($this->sValidationPattern != '') &&(!preg_match('/'.$this->sValidationPattern.'/', $aValues[$this->sCode])) ) { $aValues[$this->sCode] = $this->defaultValue; } } } class DesignerLongTextField extends DesignerTextField { public function Render(WebPage $oP, $sFormId, $sRenderMode='dialog') { $sId = $this->oForm->GetFieldId($this->sCode); $sName = $this->oForm->GetFieldName($this->sCode); $sPattern = addslashes($this->sValidationPattern); $sMandatory = $this->bMandatory ? 'true' : 'false'; $sReadOnly = $this->IsReadOnly() ? 'readonly' : ''; $oP->add_ready_script( << $this->sLabel, 'value' => ""); } } class DesignerComboField extends DesignerFormField { protected $aAllowedValues; protected $bMultipleSelection; protected $bOtherChoices; public function __construct($sCode, $sLabel = '', $defaultValue = '') { parent::__construct($sCode, $sLabel, $defaultValue); $this->aAllowedValues = array(); $this->bMultipleSelection = false; $this->bOtherChoices = false; $this->bAutoApply = true; } public function SetAllowedValues($aAllowedValues) { $this->aAllowedValues = $aAllowedValues; } public function MultipleSelection($bMultipleSelection = true) { $this->bMultipleSelection = $bMultipleSelection; } public function OtherChoices($bOtherChoices = true) { $this->bOtherChoices = $bOtherChoices; } public function Render(WebPage $oP, $sFormId, $sRenderMode='dialog') { $sId = $this->oForm->GetFieldId($this->sCode); $sName = $this->oForm->GetFieldName($this->sCode); $sChecked = $this->defaultValue ? 'checked' : ''; $sMandatory = $this->bMandatory ? 'true' : 'false'; $sReadOnly = $this->IsReadOnly() ? 'disabled="disabled"' : ''; if ($this->bMultipleSelection) { $sHtml = ""; $sHtml .= ""; } foreach($this->aAllowedValues as $sKey => $sDisplayValue) { if ($this->bMultipleSelection) { $sSelected = in_array($sKey, $this->defaultValue) ? 'selected' : ''; } else { $sSelected = ($sKey == $this->defaultValue) ? 'selected' : ''; } // Quick and dirty: display the menu parents as a tree $sHtmlValue = str_replace(' ', ' ', htmlentities($sDisplayValue, ENT_QUOTES, 'UTF-8')); $sHtml .= ""; } $sHtml .= ""; if ($this->bOtherChoices) { $sHtml .= '
 '; } $oP->add_ready_script( << $this->sLabel, 'value' => $sHtml); } public function ReadParam(&$aValues) { parent::ReadParam($aValues); if ($aValues[$this->sCode] == 'null') { $aValues[$this->sCode] = array(); } } } class DesignerBooleanField extends DesignerFormField { public function __construct($sCode, $sLabel = '', $defaultValue = '') { parent::__construct($sCode, $sLabel, $defaultValue); $this->bAutoApply = true; } public function Render(WebPage $oP, $sFormId, $sRenderMode='dialog') { $sId = $this->oForm->GetFieldId($this->sCode); $sName = $this->oForm->GetFieldName($this->sCode); $sChecked = $this->defaultValue ? 'checked' : ''; $sReadOnly = $this->IsReadOnly() ? 'disabled' : ''; // readonly does not work as expected on checkboxes: // readonly prevents the user from changing the input's value not its state (checked/unchecked) return array('label' => $this->sLabel, 'value' => ""); } public function ReadParam(&$aValues) { if ($this->IsReadOnly()) { $aValues[$this->sCode] = $this->defaultValue; } else { $sParamsContainer = $this->oForm->GetParamsContainer(); if ($sParamsContainer != '') { $aParams = utils::ReadParam($sParamsContainer, array(), false, 'raw_data'); if (array_key_exists($this->oForm->GetParamName($this->sCode), $aParams)) { $sValue = $aParams[$this->oForm->GetParamName($this->sCode)]; } else { $sValue = 'false'; } } else { $sValue = utils::ReadParam($this->oForm->GetParamName($this->sCode), 'false', false, 'raw_data'); } } $aValues[$this->sCode] = ($sValue == 'true'); } } class DesignerHiddenField extends DesignerFormField { public function __construct($sCode, $sLabel = '', $defaultValue = '') { parent::__construct($sCode, $sLabel, $defaultValue); } public function IsVisible() { return false; } public function Render(WebPage $oP, $sFormId, $sRenderMode='dialog') { $sId = $this->oForm->GetFieldId($this->sCode); $sName = $this->oForm->GetFieldName($this->sCode); $sChecked = $this->defaultValue ? 'checked' : ''; return array('label' =>'', 'value' => "defaultValue, ENT_QUOTES, 'UTF-8')."\">"); } } class DesignerIconSelectionField extends DesignerFormField { protected $aAllowedValues; public function __construct($sCode, $sLabel = '', $defaultValue = '') { parent::__construct($sCode, $sLabel, $defaultValue); $this->bAutoApply = true; } public function SetAllowedValues($aAllowedValues) { $this->aAllowedValues = $aAllowedValues; } public function Render(WebPage $oP, $sFormId, $sRenderMode='dialog') { $sId = $this->oForm->GetFieldId($this->sCode); $sName = $this->oForm->GetFieldName($this->sCode); $idx = 0; foreach($this->aAllowedValues as $index => $aValue) { if ($aValue['value'] == $this->defaultValue) { $idx = $index; break; } } $sJSItems = json_encode($this->aAllowedValues); if (!$this->IsReadOnly()) { $oP->add_ready_script( <<IsReadOnly() ? 'disabled' : ''; return array('label' =>$this->sLabel, 'value' => "defaultValue}\"/>"); } } class DesignerSortableField extends DesignerFormField { protected $aAllowedValues; public function __construct($sCode, $sLabel = '', $defaultValue = '') { parent::__construct($sCode, $sLabel, $defaultValue); $this->aAllowedValues = array(); } public function SetAllowedValues($aAllowedValues) { $this->aAllowedValues = $aAllowedValues; } public function Render(WebPage $oP, $sFormId, $sRenderMode='dialog') { $bOpen = false; $sId = $this->oForm->GetFieldId($this->sCode); $sName = $this->oForm->GetFieldName($this->sCode); $sHtml = ""; foreach($this->defaultValue as $sValue) { $sHtml .= "$sValue"; } $sHtml .=""; $sIconClass = $bOpen ? 'ui-icon-circle-triangle-s' : 'ui-icon-circle-triangle-e'; $sStyle = $bOpen ? '' : 'style="display:none"'; $sHtml .= "
"; $sHtml .="
Fields
"; foreach($this->aAllowedValues as $sKey => $sDisplayValue) { $sHtml .= "$sDisplayValue"; } $sHtml .="
Trash
"; $oP->add_ready_script( << $this->sLabel, 'value' => $sHtml); } } class DesignerFormSelectorField extends DesignerFormField { protected $aSubForms; protected $defaultRealValue; // What's stored as default value is actually the index public function __construct($sCode, $sLabel = '', $defaultValue = '') { parent::__construct($sCode, $sLabel, 0); $this->defaultRealValue = $defaultValue; $this->aSubForms = array(); } public function AddSubForm($oSubForm, $sLabel, $sValue) { $idx = count($this->aSubForms); $this->aSubForms[] = array('form' => $oSubForm, 'label' => $sLabel, 'value' => $sValue); if ($sValue == $this->defaultRealValue) { // Store the index of the selected/default form $this->defaultValue = count($this->aSubForms) - 1; } } public function Render(WebPage $oP, $sFormId, $sRenderMode='dialog') { $sId = $this->oForm->GetFieldId($this->sCode); $sName = $this->oForm->GetFieldName($this->sCode); $sReadOnly = $this->IsReadOnly() ? 'disabled="disabled"' : ''; $sHtml = ""; if ($sRenderMode == 'property') { $sHtml .= ''; } foreach($this->aSubForms as $sKey => $aFormData) { $sId = $this->oForm->GetFieldId($this->sCode); $sStyle = ($sKey == $this->defaultValue) ? '' : 'style="display:none"'; $oSubForm = $aFormData['form']; $oSubForm->SetParentForm($this->oForm); $oSubForm->CopySubmitParams($this->oForm); $oSubForm->SetPrefix($this->oForm->GetPrefix().$sKey.'_'); if ($sRenderMode == 'property') { $sHtml .= ""; $sHtml .= $oSubForm->RenderAsPropertySheet($oP, true); } else { $sHtml .= "
"; $sHtml .= $oSubForm->Render($oP, true); $sHtml .= "
"; } } $oP->add_ready_script( << $this->sLabel, 'value' => $sHtml); } public function ReadParam(&$aValues) { parent::ReadParam($aValues); $sKey = $aValues[$this->sCode]; $aValues[$this->sCode] = $this->aSubForms[$sKey]['value']; $this->aSubForms[$sKey]['form']->SetPrefix($this->oForm->GetPrefix().$sKey.'_'); $this->aSubForms[$sKey]['form']->SetParentForm($this->oForm); $this->aSubForms[$sKey]['form']->ReadParams($aValues); } } class DesignerSubFormField extends DesignerFormField { protected $oSubForm; public function __construct($sLabel, $oSubForm) { parent::__construct('', $sLabel, ''); $this->oSubForm = $oSubForm; } public function Render(WebPage $oP, $sFormId, $sRenderMode='dialog') { $this->oSubForm->SetParentForm($this->oForm); $this->oSubForm->CopySubmitParams($this->oForm); if ($sRenderMode == 'property') { $sHtml = $this->oSubForm->RenderAsPropertySheet($oP, true); } else { $sHtml = $this->oSubForm->Render($oP, true); } return array('label' => $this->sLabel, 'value' => $sHtml); } public function ReadParam(&$aValues) { $this->oSubForm->SetParentForm($this->oForm); $this->oSubForm->ReadParams($aValues); } } ?>