diff --git a/application/applicationcontext.class.inc.php b/application/applicationcontext.class.inc.php index b24fafd3a..87c02b1fa 100644 --- a/application/applicationcontext.class.inc.php +++ b/application/applicationcontext.class.inc.php @@ -24,19 +24,23 @@ * @license http://opensource.org/licenses/AGPL-3.0 */ +use Combodo\iTop\Application\UI\Component\Input\InputFactory; +use Combodo\iTop\Application\UI\Layout\UIContentBlock; +use Combodo\iTop\Application\UI\UIBlock; + require_once(APPROOT."/application/utils.inc.php"); /** * Interface for directing end-users to the relevant application - */ + */ interface iDBObjectURLMaker { - /** - * @param string $sClass - * @param string $iId - * - * @return string - */ + /** + * @param string $sClass + * @param string $iId + * + * @return string + */ public static function MakeObjectURL($sClass, $iId); } @@ -207,24 +211,39 @@ class ApplicationContext */ public function GetForPostParams() { - return json_encode( $this->aValues); + return json_encode($this->aValues); } + /** * Returns the context as sequence of input tags to be inserted inside a
tag + * * @return string The context as a sequence of tags */ public function GetForForm() { $sContext = ""; - foreach($this->aValues as $sName => $sValue) - { + foreach ($this->aValues as $sName => $sValue) { $sContext .= "\n"; } return $sContext; } + /** + * Returns the context as sequence of input tags to be inserted inside a tag + * + */ + public function GetForFormBlock(): UIBlock + { + $oContext = new UIContentBlock(); + foreach ($this->aValues as $sName => $sValue) { + $oContext->AddSubBlock(InputFactory::MakeForHidden('c[$sName]', utils::HtmlEntities($sValue))); + } + return $oContext; + } + /** * Returns the context as a hash array 'parameter_name' => value + * * @return array The context information */ public function GetAsHash() diff --git a/css/backoffice/components/_all.scss b/css/backoffice/components/_all.scss index 63f4b351a..0539711ae 100644 --- a/css/backoffice/components/_all.scss +++ b/css/backoffice/components/_all.scss @@ -16,4 +16,6 @@ @import "tabcontainer"; @import "tab"; @import "ajaxtab"; -@import "title"; \ No newline at end of file +@import "title"; +@import "form"; +@import "input"; \ No newline at end of file diff --git a/css/backoffice/components/_form.scss b/css/backoffice/components/_form.scss new file mode 100644 index 000000000..2b1c120e8 --- /dev/null +++ b/css/backoffice/components/_form.scss @@ -0,0 +1,4 @@ +/*! + * copyright Copyright (C) 2010-2020 Combodo SARL + * license http://opensource.org/licenses/AGPL-3.0 + */ diff --git a/css/backoffice/components/_input.scss b/css/backoffice/components/_input.scss new file mode 100644 index 000000000..2b1c120e8 --- /dev/null +++ b/css/backoffice/components/_input.scss @@ -0,0 +1,4 @@ +/*! + * copyright Copyright (C) 2010-2020 Combodo SARL + * license http://opensource.org/licenses/AGPL-3.0 + */ diff --git a/datamodels/2.x/itop-config/config.php b/datamodels/2.x/itop-config/config.php index 0ea68d1c8..dd8ebc3cd 100644 --- a/datamodels/2.x/itop-config/config.php +++ b/datamodels/2.x/itop-config/config.php @@ -26,7 +26,9 @@ use Combodo\iTop\Application\UI\Component\Alert\AlertFactory; use Combodo\iTop\Application\UI\Component\Button\ButtonFactory; +use Combodo\iTop\Application\UI\Component\Form\Form; use Combodo\iTop\Application\UI\Component\Html\Html; +use Combodo\iTop\Application\UI\Component\Input\InputFactory; use Combodo\iTop\Application\UI\Component\Title\TitleFactory; use Combodo\iTop\Config\Validator\iTopConfigAstValidator; use Combodo\iTop\Config\Validator\iTopConfigSyntaxValidator; @@ -167,23 +169,22 @@ try { $sOriginalConfigEscaped = htmlentities($sOriginalConfig, ENT_QUOTES, 'UTF-8'); $oP->AddUiBlock(new Html('

'.Dict::S('config-edit-intro').'

')); - $oP->add(""); - $oP->add(""); - $oP->add(""); + $oForm = new Form(); + $oForm->AddSubBlock(InputFactory::MakeForHidden('operation', 'save')); + $oForm->AddSubBlock(InputFactory::MakeForHidden('transaction_id', utils::GetNewTransactionId())); // - Cancel button $oCancelButton = ButtonFactory::MakeForSecondaryAction(Dict::S('config-cancel'), 'cancel_button', null, true, 'cancel_button'); $oCancelButton->SetOnClickJsCode("return ResetConfig();"); - $oP->AddUiBlock($oCancelButton); + $oForm->AddSubBlock($oCancelButton); // - Submit button $oSubmitButton = ButtonFactory::MakeForValidationAction(Dict::S('config-apply'), null, Dict::S('config-apply'), true, 'submit_button'); - $oP->AddUiBlock($oSubmitButton); - - $oP->add(""); - $oP->add(""); - $oP->add("
"); - $oP->add("
"); + $oForm->AddSubBlock($oSubmitButton); + $oForm->AddSubBlock(InputFactory::MakeForHidden('prev_config', $sOriginalConfigEscaped)); + $oForm->AddSubBlock(InputFactory::MakeForHidden('new_config', $sConfigEscaped)); + $oForm->AddHtml("
"); + $oP->AddUiBlock($oForm); $oP->add_script( <<<'JS' diff --git a/lib/composer/autoload_classmap.php b/lib/composer/autoload_classmap.php index 11f3933b5..66a290779 100644 --- a/lib/composer/autoload_classmap.php +++ b/lib/composer/autoload_classmap.php @@ -155,10 +155,16 @@ return array( 'Combodo\\iTop\\Application\\UI\\Component\\Breadcrumbs\\Breadcrumbs' => $baseDir . '/sources/application/UI/Component/Breadcrumbs/Breadcrumbs.php', 'Combodo\\iTop\\Application\\UI\\Component\\Button\\Button' => $baseDir . '/sources/application/UI/Component/Button/Button.php', 'Combodo\\iTop\\Application\\UI\\Component\\Button\\ButtonFactory' => $baseDir . '/sources/application/UI/Component/Button/ButtonFactory.php', + 'Combodo\\iTop\\Application\\UI\\Component\\Form\\Form' => $baseDir . '/sources/application/UI/Component/Form/Form.php', 'Combodo\\iTop\\Application\\UI\\Component\\GlobalSearch\\GlobalSearch' => $baseDir . '/sources/application/UI/Component/GlobalSearch/GlobalSearch.php', 'Combodo\\iTop\\Application\\UI\\Component\\GlobalSearch\\GlobalSearchFactory' => $baseDir . '/sources/application/UI/Component/GlobalSearch/GlobalSearchFactory.php', 'Combodo\\iTop\\Application\\UI\\Component\\GlobalSearch\\GlobalSearchHelper' => $baseDir . '/sources/application/UI/Component/GlobalSearch/GlobalSearchHelper.php', 'Combodo\\iTop\\Application\\UI\\Component\\Html\\Html' => $baseDir . '/sources/application/UI/Component/Html/Html.php', + 'Combodo\\iTop\\Application\\UI\\Component\\Input\\Input' => $baseDir . '/sources/application/UI/Component/Input/Input.php', + 'Combodo\\iTop\\Application\\UI\\Component\\Input\\InputFactory' => $baseDir . '/sources/application/UI/Component/Input/InputFactory.php', + 'Combodo\\iTop\\Application\\UI\\Component\\Input\\InputWithLabel' => $baseDir . '/sources/application/UI/Component/Input/InputWithLabel.php', + 'Combodo\\iTop\\Application\\UI\\Component\\Input\\Select' => $baseDir . '/sources/application/UI/Component/Input/Select.php', + 'Combodo\\iTop\\Application\\UI\\Component\\Input\\SelectOption' => $baseDir . '/sources/application/UI/Component/Input/SelectOption.php', 'Combodo\\iTop\\Application\\UI\\Component\\Panel\\Panel' => $baseDir . '/sources/application/UI/Component/Panel/Panel.php', 'Combodo\\iTop\\Application\\UI\\Component\\Panel\\PanelFactory' => $baseDir . '/sources/application/UI/Component/Panel/PanelFactory.php', 'Combodo\\iTop\\Application\\UI\\Component\\PopoverMenu\\NewsroomMenu\\NewsroomMenu' => $baseDir . '/sources/application/UI/Component/PopoverMenu/NewsroomMenu/NewsroomMenu.php', diff --git a/lib/composer/autoload_static.php b/lib/composer/autoload_static.php index faeb36891..eb3cf7b0f 100644 --- a/lib/composer/autoload_static.php +++ b/lib/composer/autoload_static.php @@ -385,10 +385,16 @@ class ComposerStaticInit0018331147de7601e7552f7da8e3bb8b 'Combodo\\iTop\\Application\\UI\\Component\\Breadcrumbs\\Breadcrumbs' => __DIR__ . '/../..' . '/sources/application/UI/Component/Breadcrumbs/Breadcrumbs.php', 'Combodo\\iTop\\Application\\UI\\Component\\Button\\Button' => __DIR__ . '/../..' . '/sources/application/UI/Component/Button/Button.php', 'Combodo\\iTop\\Application\\UI\\Component\\Button\\ButtonFactory' => __DIR__ . '/../..' . '/sources/application/UI/Component/Button/ButtonFactory.php', + 'Combodo\\iTop\\Application\\UI\\Component\\Form\\Form' => __DIR__ . '/../..' . '/sources/application/UI/Component/Form/Form.php', 'Combodo\\iTop\\Application\\UI\\Component\\GlobalSearch\\GlobalSearch' => __DIR__ . '/../..' . '/sources/application/UI/Component/GlobalSearch/GlobalSearch.php', 'Combodo\\iTop\\Application\\UI\\Component\\GlobalSearch\\GlobalSearchFactory' => __DIR__ . '/../..' . '/sources/application/UI/Component/GlobalSearch/GlobalSearchFactory.php', 'Combodo\\iTop\\Application\\UI\\Component\\GlobalSearch\\GlobalSearchHelper' => __DIR__ . '/../..' . '/sources/application/UI/Component/GlobalSearch/GlobalSearchHelper.php', 'Combodo\\iTop\\Application\\UI\\Component\\Html\\Html' => __DIR__ . '/../..' . '/sources/application/UI/Component/Html/Html.php', + 'Combodo\\iTop\\Application\\UI\\Component\\Input\\Input' => __DIR__ . '/../..' . '/sources/application/UI/Component/Input/Input.php', + 'Combodo\\iTop\\Application\\UI\\Component\\Input\\InputFactory' => __DIR__ . '/../..' . '/sources/application/UI/Component/Input/InputFactory.php', + 'Combodo\\iTop\\Application\\UI\\Component\\Input\\InputWithLabel' => __DIR__ . '/../..' . '/sources/application/UI/Component/Input/InputWithLabel.php', + 'Combodo\\iTop\\Application\\UI\\Component\\Input\\Select' => __DIR__ . '/../..' . '/sources/application/UI/Component/Input/Select.php', + 'Combodo\\iTop\\Application\\UI\\Component\\Input\\SelectOption' => __DIR__ . '/../..' . '/sources/application/UI/Component/Input/SelectOption.php', 'Combodo\\iTop\\Application\\UI\\Component\\Panel\\Panel' => __DIR__ . '/../..' . '/sources/application/UI/Component/Panel/Panel.php', 'Combodo\\iTop\\Application\\UI\\Component\\Panel\\PanelFactory' => __DIR__ . '/../..' . '/sources/application/UI/Component/Panel/PanelFactory.php', 'Combodo\\iTop\\Application\\UI\\Component\\PopoverMenu\\NewsroomMenu\\NewsroomMenu' => __DIR__ . '/../..' . '/sources/application/UI/Component/PopoverMenu/NewsroomMenu/NewsroomMenu.php', diff --git a/pages/preferences.php b/pages/preferences.php index 239cd7dc1..e3a8f3712 100644 --- a/pages/preferences.php +++ b/pages/preferences.php @@ -18,7 +18,9 @@ */ use Combodo\iTop\Application\UI\Component\Button\ButtonFactory; +use Combodo\iTop\Application\UI\Component\Form\Form; use Combodo\iTop\Application\UI\Component\Html\Html; +use Combodo\iTop\Application\UI\Component\Input\InputFactory; use Combodo\iTop\Application\UI\Component\Panel\Panel; use Combodo\iTop\Application\UI\Component\Title\TitleFactory; use Combodo\iTop\Application\UI\Layout\PageContent\PageContentFactory; @@ -45,48 +47,10 @@ function DisplayPreferences($oP) // ////////////////////////////////////////////////////////////////////////// $oUserLanguageBlock = new Panel(Dict::S('UI:FavoriteLanguage'), array(), 'grey', 'ibo-user-language-selection'); - $oUserLanguageStartForm = new Html('
'); - - $aLanguages = Dict::GetLanguages(); - $aSortedlang = array(); - foreach ($aLanguages as $sCode => $aLang) { - if (MetaModel::GetConfig()->Get('demo_mode')) { - if ($sCode != Dict::GetUserLanguage()) { - // Demo mode: only the current user language is listed in the available choices - continue; - } - } - $aSortedlang[$aLang['description']] = $sCode; - } - ksort($aSortedlang); - $sUserLanguageBlockSelect = ''; - $sUserLanguageBlockSelect .= '

'.Dict::S('UI:Favorites:SelectYourLanguage').'

'; - $sUserLanguageBlockSelect .= ''; - $sUserLanguageBlockSelect .= $oAppContext->GetForForm(); - $oUserLanguageBlockSelect = new Html($sUserLanguageBlockSelect); - - // - Cancel button - $oUserLanguageCancelButton = ButtonFactory::MakeForSecondaryAction(Dict::S('UI:Button:Cancel')); - $oUserLanguageCancelButton->SetOnClickJsCode("window.location.href = '$sURL'"); - // - Submit button - $oUserLanguageSubmitButton = ButtonFactory::MakeForValidationAction(Dict::S('UI:Button:Apply'), null, null, true); - - $oUserLanguageEndForm = new Html('
'); - - $oUserLanguageBlock->AddSubBlock($oUserLanguageStartForm); - $oUserLanguageBlock->AddSubBlock($oUserLanguageBlockSelect); - $oUserLanguageBlock->AddSubBlock($oUserLanguageCancelButton); - $oUserLanguageBlock->AddSubBlock($oUserLanguageSubmitButton); - $oUserLanguageBlock->AddSubBlock($oUserLanguageEndForm); - + $oUserLanguageForm = GetUserLanguageForm($oAppContext, $sURL); + $oUserLanguageBlock->AddSubBlock($oUserLanguageForm); $oContentLayout->AddMainBlock($oUserLanguageBlock); - + ////////////////////////////////////////////////////////////////////////// // // Other (miscellaneous) settings @@ -480,6 +444,48 @@ HTML $oP->SetContentLayout($oContentLayout); } +/** + * @param \ApplicationContext $oAppContext + * @param string $sURL + * + * @return \Combodo\iTop\Application\UI\Component\Form\Form + */ +function GetUserLanguageForm(ApplicationContext $oAppContext, string $sURL): Form +{ + $oUserLanguageForm = new Form(); + $oUserLanguageForm->AddSubBlock(InputFactory::MakeForHidden('operation', 'apply_language')); + + // Lang selector + $aLanguages = Dict::GetLanguages(); + $aSortedLang = array(); + foreach ($aLanguages as $sCode => $aLang) { + if (MetaModel::GetConfig()->Get('demo_mode')) { + if ($sCode != Dict::GetUserLanguage()) { + // Demo mode: only the current user language is listed in the available choices + continue; + } + } + $aSortedLang[$aLang['description']] = $sCode; + } + ksort($aSortedLang); + $oUserLanguageBlockSelect = InputFactory::MakeForSelect('language', Dict::S('UI:Favorites:SelectYourLanguage')); + foreach ($aSortedLang as $sCode) { + $bSelected = ($sCode == Dict::GetUserLanguage()); + $oUserLanguageBlockSelect->AddOption(InputFactory::MakeForSelectOption($sCode, $aLanguages[$sCode]['description'].' ('.$aLanguages[$sCode]['localized_description'].')', $bSelected)); + } + $oUserLanguageForm->AddSubBlock($oUserLanguageBlockSelect); + + $oUserLanguageForm->AddSubBlock($oAppContext->GetForFormBlock()); + // - Cancel button + $oUserLanguageCancelButton = ButtonFactory::MakeForSecondaryAction(Dict::S('UI:Button:Cancel')); + $oUserLanguageCancelButton->SetOnClickJsCode("window.location.href = '$sURL'"); + $oUserLanguageForm->AddSubBlock($oUserLanguageCancelButton); + // - Submit button + $oUserLanguageSubmitButton = ButtonFactory::MakeForValidationAction(Dict::S('UI:Button:Apply'), null, null, true); + $oUserLanguageForm->AddSubBlock($oUserLanguageSubmitButton); + return $oUserLanguageForm; +} + ///////////////////////////////////////////////////////////////////////////// // // Main program diff --git a/sources/application/UI/Component/Form/Form.php b/sources/application/UI/Component/Form/Form.php new file mode 100644 index 000000000..84af0aae0 --- /dev/null +++ b/sources/application/UI/Component/Form/Form.php @@ -0,0 +1,47 @@ +sOnSubmitJsCode = null; + } + + public function SetOnSubmitJsCode(string $sJsCode): void + { + $this->sOnSubmitJsCode = $sJsCode; + } + + /** + * @return string + */ + public function GetOnSubmitJsCode(): ?string + { + return $this->sOnSubmitJsCode; + } + + +} \ No newline at end of file diff --git a/sources/application/UI/Component/Input/Input.php b/sources/application/UI/Component/Input/Input.php new file mode 100644 index 000000000..9c61b5de7 --- /dev/null +++ b/sources/application/UI/Component/Input/Input.php @@ -0,0 +1,91 @@ +sType; + } + + /** + * @param string $sType + * + * @return Input + */ + public function SetType(string $sType): Input + { + $this->sType = $sType; + return $this; + } + + /** + * @return string + */ + public function GetName(): string + { + return $this->sName; + } + + /** + * @param string $sName + * + * @return Input + */ + public function SetName(string $sName): Input + { + $this->sName = $sName; + return $this; + } + + /** + * @return string + */ + public function GetValue(): string + { + return $this->sValue; + } + + /** + * @param string $sValue + * + * @return Input + */ + public function SetValue(string $sValue): Input + { + $this->sValue = $sValue; + return $this; + } + + +} \ No newline at end of file diff --git a/sources/application/UI/Component/Input/InputFactory.php b/sources/application/UI/Component/Input/InputFactory.php new file mode 100644 index 000000000..b0e58f32e --- /dev/null +++ b/sources/application/UI/Component/Input/InputFactory.php @@ -0,0 +1,46 @@ +SetType(Input::INPUT_HIDDEN) + ->SetName($sName) + ->SetValue($sValue); + + return $oInput; + } + + public static function MakeForSelect(string $sName, string $sLabel, ?string $sId = null): Select + { + $oInput = new Select($sId); + + $oInput->SetName($sName) + ->SetLabel($sLabel); + + return $oInput; + } + + public static function MakeForSelectOption(string $sValue, string $sLabel, bool $bSelected, ?string $sId = null): SelectOption + { + $oInput = new SelectOption($sId); + + $oInput->SetValue($sValue) + ->SetLabel($sLabel) + ->SetSelected($bSelected); + + return $oInput; + } + +} \ No newline at end of file diff --git a/sources/application/UI/Component/Input/InputWithLabel.php b/sources/application/UI/Component/Input/InputWithLabel.php new file mode 100644 index 000000000..91a16210a --- /dev/null +++ b/sources/application/UI/Component/Input/InputWithLabel.php @@ -0,0 +1,37 @@ +sLabel; + } + + /** + * @param string $sLabel + * + * @return InputWithLabel + */ + public function SetLabel(string $sLabel): InputWithLabel + { + $this->sLabel = $sLabel; + return $this; + } + +} \ No newline at end of file diff --git a/sources/application/UI/Component/Input/Select.php b/sources/application/UI/Component/Input/Select.php new file mode 100644 index 000000000..be21f1e81 --- /dev/null +++ b/sources/application/UI/Component/Input/Select.php @@ -0,0 +1,33 @@ +aOptions = []; + } + + public function AddOption(SelectOption $oOption) + { + $this->aOptions[$oOption->GetId()] = $oOption; + } + + public function GetSubBlocks() + { + return $this->aOptions; + } +} \ No newline at end of file diff --git a/sources/application/UI/Component/Input/SelectOption.php b/sources/application/UI/Component/Input/SelectOption.php new file mode 100644 index 000000000..524b0cf2f --- /dev/null +++ b/sources/application/UI/Component/Input/SelectOption.php @@ -0,0 +1,81 @@ +sValue; + } + + /** + * @param string $sValue + * + * @return SelectOption + */ + public function SetValue(string $sValue): SelectOption + { + $this->sValue = $sValue; + return $this; + } + + /** + * @return string + */ + public function GetLabel(): string + { + return $this->sLabel; + } + + /** + * @param string $sLabel + * + * @return SelectOption + */ + public function SetLabel(string $sLabel): SelectOption + { + $this->sLabel = $sLabel; + return $this; + } + + /** + * @return bool + */ + public function IsSelected(): bool + { + return $this->bSelected; + } + + /** + * @param bool $bSelected + * + * @return SelectOption + */ + public function SetSelected(bool $bSelected): SelectOption + { + $this->bSelected = $bSelected; + return $this; + } + +} \ No newline at end of file diff --git a/templates/components/form/layout.html.twig b/templates/components/form/layout.html.twig new file mode 100644 index 000000000..b5a1e546e --- /dev/null +++ b/templates/components/form/layout.html.twig @@ -0,0 +1,9 @@ +
+ {% apply spaceless %} + {% block iboContentBlockContainer %} + {% for oSubBlock in oUIBlock.GetSubBlocks() %} + {{ render_block(oSubBlock, {aPage: aPage}) }} + {% endfor %} + {% endblock %} + {% endapply %} +
\ No newline at end of file diff --git a/templates/components/input/inputwithlabel.html.twig b/templates/components/input/inputwithlabel.html.twig new file mode 100644 index 000000000..c2a7c1d8e --- /dev/null +++ b/templates/components/input/inputwithlabel.html.twig @@ -0,0 +1,4 @@ +{% extends "components/input/layout.html.twig" %} +{% block iboInputLabel %} + +{% endblock %} diff --git a/templates/components/input/layout.html.twig b/templates/components/input/layout.html.twig new file mode 100644 index 000000000..21662ece8 --- /dev/null +++ b/templates/components/input/layout.html.twig @@ -0,0 +1,5 @@ +{% block iboInputLabel %} +{% endblock %} +{% block iboInput %} + +{% endblock %} \ No newline at end of file diff --git a/templates/components/input/select.html.twig b/templates/components/input/select.html.twig new file mode 100644 index 000000000..a47106129 --- /dev/null +++ b/templates/components/input/select.html.twig @@ -0,0 +1,10 @@ +{# @copyright Copyright (C) 2010-2020 Combodo SARL #} +{# @license http://opensource.org/licenses/AGPL-3.0 #} +{% extends "components/input/inputwithLabel.html.twig" %} +{% block iboInput %} + +{% endblock %} \ No newline at end of file diff --git a/templates/components/input/selectoption.html.twig b/templates/components/input/selectoption.html.twig new file mode 100644 index 000000000..1ae2a8cd2 --- /dev/null +++ b/templates/components/input/selectoption.html.twig @@ -0,0 +1,3 @@ +{# @copyright Copyright (C) 2010-2020 Combodo SARL #} +{# @license http://opensource.org/licenses/AGPL-3.0 #} +