Extended GPL, see docs/LICENSE */
+namespace ILIAS\UI\Implementation\Component\Input\Formlet;
+
+use \ILIAS\UI\Component\Input\Input;
+/**
+ * A formlet represents one part of a form. It can be combined with other formlets
+ * to yield new formlets. Formlets are immutable, that is they can be reused in
+ * as many places as liked. All methods return fresh Formlets instead of muting
+ * the Formlets they are called upon.
+ *
+ * Todo: Rethink the name. The currently proposed "Formlet" seems to have shifted from
+ * the initial concept of formlets.
+ */
+interface IFormlet extends Input{
+ /**
+ * Internally used to get the content to be rendered by the renderer
+ *
+ * @return array
+ */
+ public function extractToView();
+
+ /**
+ * Todo: Improve this! What is name?
+ * @param string $name
+ * @return Input
+ */
+ public function setName($name);
+
+ /**
+ * Todo: Improve this! What is name?
+ * @return string
+ */
+ public function getName();
+}
diff --git a/src/UI/Implementation/Component/Input/Formlet/Renderer.php b/src/UI/Implementation/Component/Input/Formlet/Renderer.php
new file mode 100755
index 000000000000..47bfa08cfa94
--- /dev/null
+++ b/src/UI/Implementation/Component/Input/Formlet/Renderer.php
@@ -0,0 +1,36 @@
+ Extended GPL, see docs/LICENSE */
+
+namespace ILIAS\UI\Implementation\Component\Input\Formlet;
+
+use ILIAS\UI\Implementation\Render\AbstractComponentRenderer;
+use ILIAS\UI\Renderer as RendererInterface;
+use ILIAS\UI\Component;
+
+/**
+ * Class Renderer
+ * @package ILIAS\UI\Implementation\Component\Image
+ */
+class Renderer extends AbstractComponentRenderer {
+ /**
+ * @inheritdocs
+ */
+ public function render(Component\Component $component, RendererInterface $default_renderer) {
+ /**
+ * @var \ILIAS\UI\Implementation\Component\Input\Formlet\Formlet $component
+ */
+ $content = "";
+ foreach($component->extractToView() as $item){
+ $content .= $default_renderer->render($item);
+ }
+ return $content;
+ }
+
+ /**
+ * @inheritdocs
+ */
+ protected function getComponentInterfaceName() {
+ return [Component\Input\Item\Formlet\Formlet::class];
+ }
+}
diff --git a/src/UI/Implementation/Component/Input/Formlet/example.php b/src/UI/Implementation/Component/Input/Formlet/example.php
new file mode 100644
index 000000000000..735080cb4f9e
--- /dev/null
+++ b/src/UI/Implementation/Component/Input/Formlet/example.php
@@ -0,0 +1,81 @@
+formlet("test");
+$formlet = $formlet->addViewToModelMapping(
+ function($input){
+ var_dump($input);
+ return 2*$input;
+ }
+);
+$formlet = $formlet->addValidation((new V\Validation(function($input){
+ return $input == 3;//is_numeric($input);
+},"Error1")));
+
+
+$formlet = $formlet->combine($formlet->createClone("test2"));
+
+
+$formlet = $formlet->withInputFromView(["test2"=>3,"test"=>3]);
+var_dump($formlet->getMessageCollector()->getMessages());
+
+var_dump($formlet->extractToView());
+var_dump($formlet->extractToModel());
+var_dump($formlet->extractToModel());
+exit;
+/**
+$formlet = $formlet->withInputFromView("asdf asdf");
+var_dump($formlet->extractToModel());
+var_dump($formlet->isValid());
+
+
+
+
+
+$value = F::getFactory()->value()->plain("1000000");
+
+$view_to_model = new V\FunctionCallable(function($input){
+ return intval($input);
+});
+
+$model_to_view = new V\FunctionCallable(function($input){
+ return "Value: ".$input;
+
+});
+$model_to_view = $model_to_view->composeWith(new V\FunctionCallable(function
+($input){
+ return number_format ($input);
+}));
+
+$map = new R\Map($model_to_view,$view_to_model);
+
+
+var_dump($map->viewToModel($value));
+var_dump($map->modelToView($value));
+
+
+
+$view_validation = new V\FunctionCallable(function($input){
+ return is_numeric($input);
+});
+
+$model_validation = new V\FunctionCallable(function($input){
+ return is_int($input);
+
+});
+
+$validation = new R\Validation($view_validation,$model_validation);
+
+$value1 = F::getFactory()->value()->plain("1000000");
+
+$value2= F::getFactory()->value()->plain(1000000);
+
+var_dump($validation->validateView($value1));
+var_dump($validation->validateModel($value2));**/
\ No newline at end of file
diff --git a/src/UI/Implementation/Component/Input/Item/Factory.php b/src/UI/Implementation/Component/Input/Item/Factory.php
new file mode 100755
index 000000000000..892665e5f48d
--- /dev/null
+++ b/src/UI/Implementation/Component/Input/Item/Factory.php
@@ -0,0 +1,32 @@
+ Extended GPL, see docs/LICENSE */
+
+namespace ILIAS\UI\Implementation\Component\Input\Item;
+
+use ILIAS\UI\Component\Input\Item as I;
+use ILIAS\UI\Implementation\Component\ComponentHelper;
+
+/**
+ * Class Factory
+ *
+ * @package ILIAS\UI\Implementation\Component\Filter
+ */
+class Factory implements I\Factory {
+
+ use ComponentHelper;
+
+ /**
+ * @inheritdoc
+ */
+ public function field() {
+ return new Field\Factory();
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function selector() {
+ return new Selector\Factory();
+ }
+}
\ No newline at end of file
diff --git a/src/UI/Implementation/Component/Input/Item/Field/Factory.php b/src/UI/Implementation/Component/Input/Item/Field/Factory.php
new file mode 100755
index 000000000000..e989e044eadf
--- /dev/null
+++ b/src/UI/Implementation/Component/Input/Item/Field/Factory.php
@@ -0,0 +1,39 @@
+ Extended GPL, see docs/LICENSE */
+
+namespace ILIAS\UI\Implementation\Component\Input\Item\Field;
+
+use ILIAS\UI\Component\Input\Item\Field as F;
+use ILIAS\UI\Implementation\Component\ComponentHelper;
+
+/**
+ * Class Factory
+ *
+ * @package ILIAS\UI\Implementation\Component\Filter
+ */
+class Factory implements F\Factory {
+
+ use ComponentHelper;
+
+ /**
+ * @inheritdoc
+ */
+ public function text($label) {
+ return new Text($label,[]);
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function number($label) {
+ return new Number($label);
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function nameAge($id) {
+ return new NameAge($id, "");
+ }
+}
\ No newline at end of file
diff --git a/src/UI/Implementation/Component/Input/Item/Field/NameAge.php b/src/UI/Implementation/Component/Input/Item/Field/NameAge.php
new file mode 100644
index 000000000000..bc93d9b8635f
--- /dev/null
+++ b/src/UI/Implementation/Component/Input/Item/Field/NameAge.php
@@ -0,0 +1,21 @@
+ Extended GPL, see docs/LICENSE */
+
+
+namespace ILIAS\UI\Implementation\Component\Input\Item\Field;
+
+use ILIAS\UI\Component\Input\Item\Field as F;
+use ILIAS\UI\Implementation\Component\Input\Item as I;
+
+class Number extends I\Item implements F\Text {
+ /**
+ * @var string
+ */
+ protected $type = "number";
+
+ /**
+ * @inheritdoc
+ */
+ public function __construct($label) {
+ parent::__construct($label);
+ }
+}
diff --git a/src/UI/Implementation/Component/Input/Item/Field/Renderer.php b/src/UI/Implementation/Component/Input/Item/Field/Renderer.php
new file mode 100755
index 000000000000..45a841e62632
--- /dev/null
+++ b/src/UI/Implementation/Component/Input/Item/Field/Renderer.php
@@ -0,0 +1,72 @@
+ Extended GPL, see docs/LICENSE */
+
+namespace ILIAS\UI\Implementation\Component\Input\Item\Field;
+
+use ILIAS\UI\Implementation\Render\AbstractComponentRenderer;
+use ILIAS\UI\Renderer as RendererInterface;
+use ILIAS\UI\Component;
+
+/**
+ * Class Renderer
+ * Todo this is mostly experimenting
+ * @package ILIAS\UI\Implementation\Component\Image
+ */
+class Renderer extends AbstractComponentRenderer {
+ /**
+ * @inheritdocs
+ */
+ public function render(Component\Component $component, RendererInterface $default_renderer) {
+ /**
+ * @var \ILIAS\UI\Implementation\Component\Input\Item\Item $component
+ */
+ $this->checkComponent($component);
+ $tpl = $this->getTemplate("Filter/tpl.text.html", true, true);
+
+ if($component instanceof NameAge)
+ {
+ $inputs ="";
+ foreach($component->extractToView() as $option){
+ $inputs .= $default_renderer->render($option);
+ }
+ return $inputs;
+ }else{
+ //$tpl->setVariable("ID","TODO");
+ $tpl->setVariable("FOR",$component->getName());
+ $tpl->setVariable("ID",$component->getName());
+ $tpl->setVariable("VALUE",$component->getValue());
+
+
+ if($component->isValidated()){
+ if($component->isValid()){
+ $tpl->touchBlock("success");
+ }else{
+ $tpl->touchBlock("error");
+ $tpl->setVariable("VALIDATION_ERROR",
+ $component->getMessageCollector()->getMessages()[0]->getMessage());
+ }
+
+ }
+
+
+ $tpl->setVariable("LABEL",$component->getLabel());
+
+ if($component->isRequired()){
+ $tpl->setVariable("REQUIRED","required");
+ }else{
+ $tpl->setVariable("REQUIRED","");
+ }
+
+ return $tpl->get();
+ }
+
+ }
+
+ /**
+ * @inheritdocs
+ */
+ protected function getComponentInterfaceName() {
+ return [Component\Input\Item\Field\Text::class];
+ }
+}
diff --git a/src/UI/Implementation/Component/Input/Item/Field/Text.php b/src/UI/Implementation/Component/Input/Item/Field/Text.php
new file mode 100755
index 000000000000..6a03cf035f3e
--- /dev/null
+++ b/src/UI/Implementation/Component/Input/Item/Field/Text.php
@@ -0,0 +1,28 @@
+ Extended GPL, see docs/LICENSE */
+
+
+namespace ILIAS\UI\Implementation\Component\Input\Item\Field;
+
+use ILIAS\UI\Component\Input\Item\Field as F;
+use ILIAS\UI\Implementation\Component\Input\Item as I;
+
+/**
+ * Class Text
+ * @package ILIAS\UI\Implementation\Component\Input\Item\Field
+ */
+class Text extends I\Item implements F\Text {
+
+ /**
+ * @var string
+ */
+ protected $type = "text";
+
+ /**
+ * @inheritdoc
+ */
+ public function __construct($label) {
+ parent::__construct($label);
+ }
+}
diff --git a/src/UI/Implementation/Component/Input/Item/Item.php b/src/UI/Implementation/Component/Input/Item/Item.php
new file mode 100755
index 000000000000..ca4480b5cb9c
--- /dev/null
+++ b/src/UI/Implementation/Component/Input/Item/Item.php
@@ -0,0 +1,58 @@
+checkStringArg("label",$label);
+ $this->label = $label;
+ parent::__construct($children);
+ }
+
+ /**
+ * @inheritdocs
+ */
+ public function getLabel(){
+ return $this->label;
+ }
+
+ /**
+ * @inheritdocs
+ */
+ public function required(){
+ $clone = clone $this;
+ $clone->required = true;
+ $clone = $clone->addValidation(new F\NotEmpty());
+ return $clone;
+ }
+
+ /**
+ * @inheritdocs
+ */
+ public function isRequired(){
+ return $this->required;
+ }
+}
diff --git a/src/UI/Implementation/Component/Input/Item/Selector/Factory.php b/src/UI/Implementation/Component/Input/Item/Selector/Factory.php
new file mode 100755
index 000000000000..e4daaefc29bf
--- /dev/null
+++ b/src/UI/Implementation/Component/Input/Item/Selector/Factory.php
@@ -0,0 +1,38 @@
+ Extended GPL, see docs/LICENSE */
+
+namespace ILIAS\UI\Implementation\Component\Input\Item\Selector;
+
+use ILIAS\UI\Component\Input\Item\Selector as S;
+
+/**
+ * Class Factory
+ *
+ * @package ILIAS\UI\Implementation\Component\Filter
+ */
+class Factory implements S\Factory {
+
+ public function repository(){
+
+ }
+
+ public function radioGroup($id,$label,$radio_options){
+ return new RadioGroup($id,$label,$radio_options);
+
+ }
+
+ /**
+ * ---
+ * description:
+ * purpose: >
+ * Todo
+ *
+ * ----
+ * @param RadioOption[] $radio_options Radio options to be offered by the radio Group
+ * @return \ILIAS\UI\Component\Input\Item\Selector\RadioGroup
+ */
+ public function radioOption($id,$label){
+ return new RadioOption($id,$label);
+ }
+}
\ No newline at end of file
diff --git a/src/UI/Implementation/Component/Input/Item/Selector/RadioGroup.php b/src/UI/Implementation/Component/Input/Item/Selector/RadioGroup.php
new file mode 100755
index 000000000000..90a3bf4c7c9e
--- /dev/null
+++ b/src/UI/Implementation/Component/Input/Item/Selector/RadioGroup.php
@@ -0,0 +1,28 @@
+inGroup($this->getId());
+ $children_copy[] = $child;
+ }
+ parent::__construct($id,$label,$children_copy);
+ }
+}
diff --git a/src/UI/Implementation/Component/Input/Item/Selector/RadioOption.php b/src/UI/Implementation/Component/Input/Item/Selector/RadioOption.php
new file mode 100755
index 000000000000..a9e0b83254a1
--- /dev/null
+++ b/src/UI/Implementation/Component/Input/Item/Selector/RadioOption.php
@@ -0,0 +1,25 @@
+group_id = $id;
+ }
+
+ public function getGroup(){
+ return $this->group_id;
+ }
+
+}
diff --git a/src/UI/Implementation/Component/Input/Item/Selector/Renderer.php b/src/UI/Implementation/Component/Input/Item/Selector/Renderer.php
new file mode 100755
index 000000000000..85fa8adcc7cd
--- /dev/null
+++ b/src/UI/Implementation/Component/Input/Item/Selector/Renderer.php
@@ -0,0 +1,82 @@
+checkComponent($component);
+
+ if($component instanceof Component\Input\Item\Selector\RadioGroup)
+ {
+ $tpl = $this->getTemplate("Item/Selector/tpl.radio_group.html", true, true);
+
+ $options = "";
+
+ foreach($component->extractToView() as $option){
+ $options .= $default_renderer->render($option);
+ }
+ $tpl->setVariable("OPTIONS",$options);
+ }else{
+ $tpl = $this->getTemplate("Item/Selector/tpl.radio_option.html", true, true);
+ $tpl->setVariable("GROUP",$component->getGroup());
+
+
+ }
+
+
+
+ //$tpl->setVariable("ID","TODO");
+ $tpl->setVariable("FOR",$component->getId());
+ $tpl->setVariable("ID",$component->getId());
+ $tpl->setVariable("VALUE",$component->extractToView());
+
+
+ if($component->isValidated()){
+ if($component->isValid()){
+ $tpl->touchBlock("success");
+ }else{
+ $tpl->touchBlock("error");
+ $tpl->setVariable("VALIDATION_ERROR",
+ $component->getMessageCollector()->getMessages()[0]->getMessage());
+ }
+
+ }
+
+
+ $tpl->setVariable("LABEL",$component->getLabel());
+
+ if($component->isRequired()){
+ $tpl->setVariable("REQUIRED","required");
+ }else{
+ $tpl->setVariable("REQUIRED","");
+ }
+
+ return $tpl->get();
+ }
+
+ /**
+ * @inheritdocs
+ */
+ protected function getComponentInterfaceName() {
+ return [
+ Component\Input\Item\Selector\RadioOption::class,
+ Component\Input\Item\Selector\RadioGroup::class,
+ ];
+ }
+}
diff --git a/src/UI/Implementation/Component/Input/Validation/Custom.php b/src/UI/Implementation/Component/Input/Validation/Custom.php
new file mode 100755
index 000000000000..2ff2c14372ae
--- /dev/null
+++ b/src/UI/Implementation/Component/Input/Validation/Custom.php
@@ -0,0 +1,9 @@
+ Extended GPL, see docs/LICENSE */
+
+namespace ILIAS\UI\Implementation\Component\Input\Validation;
+
+use ILIAS\UI\Component\Input\Validation as I;
+use ILIAS\UI\Implementation\Component\ComponentHelper;
+
+/**
+ * Class Factory
+ *
+ * @package ILIAS\UI\Implementation\Component\Filter
+ */
+class Factory implements \ILIAS\UI\Component\Input\Validation\Factory {
+
+ use ComponentHelper;
+
+ /**
+ * @inheritdoc
+ */
+ public function custom(callable $validation, $message) {
+ return new Custom($validation, $message);
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function Regex($regex) {
+ return new Regex($regex);
+
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function notEmpty() {
+ return new notEmpty();
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function equals($to_be_equaled) {
+ return new Equals($to_be_equaled);
+ }
+}
\ No newline at end of file
diff --git a/src/UI/Implementation/Component/Input/Validation/NotEmpty.php b/src/UI/Implementation/Component/Input/Validation/NotEmpty.php
new file mode 100755
index 000000000000..a6022fc85e02
--- /dev/null
+++ b/src/UI/Implementation/Component/Input/Validation/NotEmpty.php
@@ -0,0 +1,19 @@
+method = $f->functionValue($function);
+ $this->message_text = $message_text;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function getMessageText(){
+ return $this->message_text;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function getValidationMethod(){
+ return $this->method;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function invert(){
+ $clone = clone $this;
+ $f = new F\Factory();
+ $invert = $f->invert();
+ $clone->method = $invert->apply($this->method);
+ return $clone;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function validate($value, V\ValidationMessageCollector $collector, Item $item){
+ if($this->method->apply($value)->get()){
+ return true;
+ }
+
+ $collector->addMessage(new ValidationMessage($this->getMessageText(), $item));
+ return false;
+ }
+}
\ No newline at end of file
diff --git a/src/UI/Implementation/Component/Input/Validation/ValidationMessage.php b/src/UI/Implementation/Component/Input/Validation/ValidationMessage.php
new file mode 100644
index 000000000000..2e93da754422
--- /dev/null
+++ b/src/UI/Implementation/Component/Input/Validation/ValidationMessage.php
@@ -0,0 +1,40 @@
+message = $message;
+ $this->item = $item;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function getMessage(){
+ return $this->message;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function getItem(){
+ return $this->item;
+ }
+}
\ No newline at end of file
diff --git a/src/UI/Implementation/Component/Input/Validation/ValidationMessageCollector.php b/src/UI/Implementation/Component/Input/Validation/ValidationMessageCollector.php
new file mode 100644
index 000000000000..29f5c41d7284
--- /dev/null
+++ b/src/UI/Implementation/Component/Input/Validation/ValidationMessageCollector.php
@@ -0,0 +1,69 @@
+messages[] = $message;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function getMessages(){
+ return $this->messages;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function join(V\ValidationMessageCollector $collector){
+ $this->messages = array_merge($this->messages,$collector->getMessages());
+ }
+
+ /**
+ * Iterator implementations
+ *
+ * @return bool
+ */
+ public function valid() {
+ return current($this->messages) !== false;
+ }
+
+ /**
+ * @return ValidationMessage
+ */
+ public function key() {
+ return key($this->messages);
+ }
+
+ /**
+ * @return ValidationMessage
+ */
+ public function current() {
+ return current($this->messages);
+ }
+
+ public function next() {
+ next($this->messages);
+ }
+
+ public function rewind() {
+ reset($this->messages);
+ }
+}
\ No newline at end of file
diff --git a/src/UI/Implementation/Component/Input/Validation/Validations.php b/src/UI/Implementation/Component/Input/Validation/Validations.php
new file mode 100644
index 000000000000..8078d14f887f
--- /dev/null
+++ b/src/UI/Implementation/Component/Input/Validation/Validations.php
@@ -0,0 +1,67 @@
+validations = $validations;
+ }
+
+ /**
+ * @param Validation $validation
+ * @return Validations
+ */
+ public function addValidation(Validation $validation){
+ $clone = clone $this;
+ $clone->validations[] = $validation;
+ return $clone;
+ }
+
+ /**
+ * Performs the actual validation with all the validations given in sequence.
+ *
+ * @param $value
+ * @param $collector
+ * @param $item
+ * @return bool
+ */
+ public function validate($value, $collector,$item){
+ $valid = true;
+ foreach($this->validations as $validation){
+ if(!$validation->validate($value,$collector,$item)){
+ $valid = false;
+ }
+ }
+ return $valid;
+ }
+
+ /**
+ * @return F\FunctionValue
+ */
+ public function getValidations()
+ {
+ return $this->validations;
+ }
+
+}
diff --git a/src/UI/Implementation/Factory.php b/src/UI/Implementation/Factory.php
index f9eae9e94a62..6a619f8d0091 100644
--- a/src/UI/Implementation/Factory.php
+++ b/src/UI/Implementation/Factory.php
@@ -89,4 +89,11 @@ public function modal() {
return new Component\Modal\Factory(new SignalGenerator());
}
+ /**
+ * @inheritdoc
+ */
+ public function input()
+ {
+ return new Component\Input\Factory();
+ }
}
diff --git a/src/UI/examples/Input/Container/Form/Standard/base.php b/src/UI/examples/Input/Container/Form/Standard/base.php
new file mode 100755
index 000000000000..76c1adba83c9
--- /dev/null
+++ b/src/UI/examples/Input/Container/Form/Standard/base.php
@@ -0,0 +1,92 @@
+ui()->factory();
+ $renderer = $DIC->ui()->renderer();
+
+ //Collecting all inputs that will be stored in the form
+ $items = [];
+
+ //Minimal textfield
+ $items[] = $f->input()->item()->field()->text("Minimal");
+
+ //Required textfield with default value and standard validation
+ $items[] = $f->input()->item()->field()->text("Required")
+ ->required();
+
+ //Textfield with default value and standard validation
+ $items[] = $f->input()->item()->field()->text("Default Value and Validation")
+ ->required()
+ ->withValue(1)
+ ->addValidation($f->input()->validation()->equals(3));
+
+ //Required textfield with custom validation
+ $items[] = $f->input()->item()->field()->text("Bigger than 3")
+ ->required()
+ ->withValue(1)->addValidation(
+ $f->input()->validation()->custom(
+ function ($input){
+ return $input > 3;
+ },"Not bigger than 3"));
+
+ //Textfield with chained mapping. Will convert input to int, double it and wrap
+ //some text around it.
+ $items[] = $f->input()->item()->field()->text("Combined Mapping")
+ ->withValue(3)
+ ->addMapping(
+ function($input){
+ return intval($input)*2;
+ })
+ ->addMapping(
+ function($input){
+ return "Output to Model is Input times 2: ".$input;
+ });
+
+ //Combined Input with chained mapping. First map into an array, then into some object.
+ $structured_output = new stdClass();
+
+ $item1 = $f->input()->item()->field()->text("Part of Combined Input");
+
+ $items[] = $item1->combine($item1)
+ ->addMapping(
+ function($input){
+ return ["item 1"=>$input[0],"item 2"=>$input[1]];
+ })
+ ->addMapping(
+ function($input) use ($structured_output) {
+ $structured_output->item1 = $input["item 1"];
+ $structured_output->item2 = $input["item 2"];
+ });
+
+ //Create form with inputs
+ $form = $f->input()->container()->form()->standard("#","Test Form",$items);
+
+
+ //Show some output if form has been sent;
+ $output = "";
+ if($_POST){
+ //Store post input into form. The input will be validated automatically.
+ //Todo, the the key test is due to yet improper handling of keys.
+ $form = $form->withInputFromView($_POST['test']);
+ if($form->isValid()){
+ $output .= "Array: ";
+ $output .=print_r($form->map(),true)."";
+ $output .= "Object: ";
+ $output .=print_r($structured_output,true)."";
+ }else{
+ $output .= "Invalid Input";
+
+ foreach($form->getMessageCollector() as $message){
+ //Todo: there is no clear concept yet for item name.
+ $output .= $message->getItem()->getName().":";
+ $output .= $message->getMessage()."";
+ }
+ }
+ }
+
+ return $renderer->render($form).$output;
+}
diff --git a/src/UI/examples/Input/Container/Form/Sub/base.php b/src/UI/examples/Input/Container/Form/Sub/base.php
new file mode 100644
index 000000000000..0e071083cfa0
--- /dev/null
+++ b/src/UI/examples/Input/Container/Form/Sub/base.php
@@ -0,0 +1,38 @@
+ui()->factory();
+ $renderer = $DIC->ui()->renderer();
+/**
+ $items = [];
+ $options = [];
+ $options[] = $f->input()->item()->selector()->radioOption("radio_option1", "Radio 1");
+ $options[] = $f->input()->item()->selector()->radioOption("radio_option2","Radio 2 Sub 2")->combineWithSubform(
+ $f->input()->container()->form()->sub(
+ [$f->input()->item()->field()->text("id15","Section Sub Sub Textfield 1")]
+ ));
+
+ $items[] = $f->input()->item()->selector()->radioGroup("radio_group","Radio Group", $options);
+
+
+ $form = $f->input()->container()->form()->standard("#","Test Form",$items);
+
+ $output = "";
+ if($_POST){
+ $form->withInputFromView($_POST);
+ if($form->isValid()){
+ foreach($form->extractToModel() as $out){
+ $output .= $out;
+ }
+
+ }else{
+ $output .= "Invalid Input";
+ }
+ }**/
+
+ return "";//$renderer->render($form).$output;
+}
diff --git a/src/UI/examples/Input/Item/Field/Text/base.php b/src/UI/examples/Input/Item/Field/Text/base.php
new file mode 100755
index 000000000000..1eab71c0eb43
--- /dev/null
+++ b/src/UI/examples/Input/Item/Field/Text/base.php
@@ -0,0 +1,30 @@
+ui()->factory();
+ $renderer = $DIC->ui()->renderer();
+
+ //Genarating and rendering the text input
+ $text_input = $f->input()->item()->field()->text("id","Textfield");
+ $text_input->withInputFromModel(["id"=>"test"]);
+ $html = $renderer->render($text_input);
+
+ $text_input = $f->input()->item()->field()->text("id","Textfield");
+ $text_input = $text_input->addValidation(
+ $f->input()->validation()->equals(3));
+
+
+ $text_input->withInputFromView(["id"=>"testView"]);
+
+ $html .= $renderer->render($text_input);
+
+ $text_input->withInputFromView(["id"=>"3"]);
+
+ $html .= $renderer->render($text_input);
+
+ return $html;
+}
diff --git a/src/UI/examples/Modal/Interruptive/async.js b/src/UI/examples/Modal/Interruptive/async.js
new file mode 100644
index 000000000000..257f1b30924f
--- /dev/null
+++ b/src/UI/examples/Modal/Interruptive/async.js
@@ -0,0 +1,16 @@
+il.Async.get = function(url, callback){
+ $.ajax({
+ type: "GET",
+ url: url,
+ }).done(function (return_data) {
+ if (return_data.success) {
+ $("body").append(return_data.content);
+ if (callback instanceof Function) {
+ //This would be probably the show action of the Modal
+ callback();
+ }
+ }
+ else {
+ //Some error processing
+ }});
+}
diff --git a/src/UI/examples/Modal/Interruptive/show_modal_on_button_click.php b/src/UI/examples/Modal/Interruptive/show_modal_on_button_click.php
index fc034b3266ff..61af1d61c8ce 100644
--- a/src/UI/examples/Modal/Interruptive/show_modal_on_button_click.php
+++ b/src/UI/examples/Modal/Interruptive/show_modal_on_button_click.php
@@ -1,30 +1,28 @@
ui()->factory();
- $renderer = $DIC->ui()->renderer();
- $message = 'Are you sure you want to delete the following items?';
- $form_action = $DIC->ctrl()->getFormActionByClass('ilsystemstyledocumentationgui');
- $icon = $factory->image()->standard('./templates/default/images/icon_crs.svg', '');
- $modal = $factory->modal()->interruptive('My Title', $message, $form_action)
- ->withAffectedItems(array(
- $factory->modal()->interruptiveItem(10, 'Course 1', $icon, 'Some description text'),
- $factory->modal()->interruptiveItem(20, 'Course 2', $icon, 'Another description text'),
- $factory->modal()->interruptiveItem(30, 'Course 3', $icon, 'Last but not least, a description'),
- ));
- $button = $factory->button()->standard('Show Modal', '')
- ->withOnClick($modal->getShowSignal());
+ global $DIC;
+ $factory = $DIC->ui()->factory();
+ $renderer = $DIC->ui()->renderer();
+ $content = $factory->legacy('This modal was opened on button click');
+ $modal = $factory->modal()->interruptive('Modal Title', $content)
+ ->withActionButton($factory->button()->primary('Delete', ''));
+ $button = $factory->button()->standard('Open Modal', '');
+
+ return $renderer->render($button->triggerAction($modal->show()));
+}
+
+$button->triggerAction($modal->showAsync($returnURL));
+
+
+function showAsync($returnURL)
+{
+ $action = new TriggerAction($this);
+ $action->setJavascriptBinding(function ($id) {
+ return "il.Async.get($returnURL);";
+ });
+
+ return $action;
+}
- // Display POST data of affected items in a panel
- $panel = '';
- if (isset($_POST['interruptive_items'])) {
- $panel = $factory->panel()->standard(
- 'Affected Items',
- $factory->legacy(print_r($_POST['interruptive_items'], true))
- );
- $panel = $renderer->render($panel);
- }
- return $renderer->render([$button, $modal]) . $panel;
-}
\ No newline at end of file
diff --git a/src/UI/templates/default/Input/Filter/tpl.text.html b/src/UI/templates/default/Input/Filter/tpl.text.html
new file mode 100755
index 000000000000..0f164b4fda1a
--- /dev/null
+++ b/src/UI/templates/default/Input/Filter/tpl.text.html
@@ -0,0 +1,11 @@
+
\ No newline at end of file
diff --git a/src/UI/templates/default/Input/Form/tpl.section.html b/src/UI/templates/default/Input/Form/tpl.section.html
new file mode 100755
index 000000000000..5dd2c8e38dae
--- /dev/null
+++ b/src/UI/templates/default/Input/Form/tpl.section.html
@@ -0,0 +1,4 @@
+
+{CONTENT}
\ No newline at end of file
diff --git a/src/UI/templates/default/Input/Form/tpl.standard.html b/src/UI/templates/default/Input/Form/tpl.standard.html
new file mode 100755
index 000000000000..bb6f688f4b07
--- /dev/null
+++ b/src/UI/templates/default/Input/Form/tpl.standard.html
@@ -0,0 +1,17 @@
+
\ No newline at end of file
diff --git a/src/UI/templates/default/Input/Form/tpl.sub.html b/src/UI/templates/default/Input/Form/tpl.sub.html
new file mode 100755
index 000000000000..9e03b00aba9d
--- /dev/null
+++ b/src/UI/templates/default/Input/Form/tpl.sub.html
@@ -0,0 +1,7 @@
+
+ {CONTENT}
+
+
+
+
+
\ No newline at end of file
diff --git a/src/UI/templates/default/Input/Item/Selector/tpl.radio_group.html b/src/UI/templates/default/Input/Item/Selector/tpl.radio_group.html
new file mode 100755
index 000000000000..4c472b046a59
--- /dev/null
+++ b/src/UI/templates/default/Input/Item/Selector/tpl.radio_group.html
@@ -0,0 +1,10 @@
+
\ No newline at end of file
diff --git a/src/UI/templates/default/Input/Item/Selector/tpl.radio_option.html b/src/UI/templates/default/Input/Item/Selector/tpl.radio_option.html
new file mode 100755
index 000000000000..806172023fec
--- /dev/null
+++ b/src/UI/templates/default/Input/Item/Selector/tpl.radio_option.html
@@ -0,0 +1,8 @@
+
+
+
+ {LABEL}
+
+
{VALIDATION_ERROR}
+
{DESCRIPTION}
+
\ No newline at end of file
diff --git a/tests/UI/Base.php b/tests/UI/Base.php
index 12532bba96b7..fce43d500db5 100644
--- a/tests/UI/Base.php
+++ b/tests/UI/Base.php
@@ -30,6 +30,7 @@ public function image() {}
public function legacy($content) {}
public function panel() {}
public function modal() {}
+ public function input() {}
}
class LoggingRegistry implements ResourceRegistry {
diff --git a/tests/UI/Component/Input/FunctionValueTest.php b/tests/UI/Component/Input/FunctionValueTest.php
new file mode 100644
index 000000000000..ab9dd8c3fe0c
--- /dev/null
+++ b/tests/UI/Component/Input/FunctionValueTest.php
@@ -0,0 +1,218 @@
+
+ *
+ * This software is licensed under The MIT License. You should have received
+ * a copy of the along with the code."
+ *
+ * See: https://github.com/lechimp-p/php-formlets
+ */
+namespace ILIAS\UI\Implementation\Component\Input\Formlet\Factory\Test\Value;
+
+require_once("libs/composer/vendor/autoload.php");
+
+use \ILIAS\UI\Implementation\Component\Input\Formlet\FunctionValue\Factory as F;
+use PHPUnit_Framework_TestCase;
+
+/**
+ * Class PlainValueTest
+ * @package ILIAS\UI\Implementation\Component\Input\Formlet\Factory\Test\Value
+ */
+class FunctionValueTest extends PHPUnit_Framework_TestCase {
+ /**
+ * @return array
+ */
+ public function getMultiplyFunction() {
+ return F::functionValue(function($a,$b){
+ return $a*$b;
+ });
+ }
+
+ /**
+ * @return \ILIAS\UI\Implementation\Component\Input\Formlet\FunctionValue\FunctionValue
+ */
+ public function getDivideFunction(){
+ return F::functionValue(function($a,$b){
+ return $a/$b;
+ });
+ }
+
+ /**
+ * @return \ILIAS\UI\Implementation\Component\Input\Formlet\FunctionValue\FunctionValue
+ */
+ public function getEqualsFunction(){
+ return F::functionValue(function($a,$b){
+ return $a==$b;
+ });
+ }
+
+ public function testGet(){
+ $const = F::constant(5);
+ $this->assertEquals(5,$const->get());
+ }
+
+ public function testSingleApply(){
+ $id = F::identity();
+ $this->assertEquals(3,$id->apply(3)->get());
+ }
+
+ public function testMultiApply1(){
+ $mult = $this->getMultiplyFunction();
+ $this->assertEquals(12,$mult->apply(3)->apply(4)->get());
+ }
+
+ public function testMultiApply2(){
+ $equals = $this->getEqualsFunction();
+ $this->assertTrue($equals->apply(3)->apply(3)->get());
+ $this->assertFalse($equals->apply(3)->apply(4)->get());
+
+ }
+
+ public function testComposeApply1(){
+ $invert = F::invert();
+ $equals = $this->getEqualsFunction();
+
+ $this->assertTrue($invert
+ ->apply($equals)
+ ->apply(4)
+ ->apply(3)
+ ->get()
+ );
+ }
+
+ public function testComposeApply2(){
+ $mult = $this->getMultiplyFunction();
+ $fun = $mult
+ ->apply(4)
+ ->apply($mult)
+ ->apply(4)
+ ->apply(3);
+ $this->assertEquals(48, $fun->get());
+
+ }
+
+ public function testComposeApply3(){
+ $mult = $this->getMultiplyFunction();
+
+ $this->assertEquals(48,$mult
+ ->apply($mult)
+ ->apply(4)
+ ->apply(4)
+ ->apply(3)
+ ->get()
+ );
+ }
+
+ public function testComposeApply4(){
+ $mult = $this->getMultiplyFunction();
+ $divide = $this->getDivideFunction();
+
+ $this->assertEquals(16,$mult
+ ->apply(4)
+ ->apply($divide)
+ ->apply(12)
+ ->apply(3)
+ ->get()
+ );
+ }
+
+ public function testComposeApply5()
+ {
+ $mult = $this->getMultiplyFunction();
+ $divide = $this->getDivideFunction();
+
+ $this->assertEquals(1, $mult
+ ->apply($divide)
+ ->apply(4)
+ ->apply(12)
+ ->apply(3)
+ ->get()
+ );
+ }
+
+ public function testComposeEqualsApply(){
+ $mult = $this->getMultiplyFunction();
+ $div = $this->getDivideFunction();
+
+ $composed = F::compose($mult,2,$div,12,3);
+
+
+ $this->assertEquals(8,$composed->get());
+ $this->assertEquals(
+ $mult->apply(2)->apply($div)->apply(12)->apply(3)->get(),
+ $composed->get()
+ );
+ }
+
+ public function testCompose1(){
+ $invert = F::invert();
+ $equals = $this->getEqualsFunction();
+
+ $composed = F::compose($invert,$equals,4,3);
+
+ $this->assertTrue($composed->get());
+ }
+
+ public function testCompose2(){
+ $mult = $this->getMultiplyFunction();
+ $composed = F::compose($mult,4,$mult,4,3);
+
+ $this->assertEquals(48, $composed->get());
+ }
+
+ public function testCompose3(){
+ $mult = $this->getMultiplyFunction();
+ $composed = F::compose($mult,$mult,4,4,3);
+ $this->assertEquals(48,$composed->get());
+ }
+
+ public function testCompose4(){
+ $mult = $this->getMultiplyFunction();
+ $divide = $this->getDivideFunction();
+ $composed = F::compose($mult,4,$divide,12,3);
+
+ $this->assertEquals(16,$composed->get());
+ }
+
+ public function testCompose5()
+ {
+ $mult = $this->getMultiplyFunction();
+ $divide = $this->getDivideFunction();
+ $composed = F::compose($mult,$divide,4,12,3);
+ $this->assertEquals(1, $composed->get());
+ }
+
+ public function testComposeVariant1()
+ {
+ $comp = $this->getEqualsFunction();
+ $divide = $this->getDivideFunction();
+
+ $devision_equals_3 = F::compose($comp,3,$divide);
+
+ $this->assertTrue( $devision_equals_3->apply(9)->apply(3)->get());
+ $this->assertFalse( $devision_equals_3->apply(12)->apply(3)->get());
+
+ }
+
+ public function testExplodeExample(){
+ $explode = F::functionValue("explode", 2);
+
+ $explodeBySpace = $explode->apply(" ");
+ $res = $explodeBySpace->apply("foo bar");
+
+ $this->assertEquals(['foo','bar'],$res->get());
+ }
+
+ public function testDescriptionExample(){
+ $mult = $this->getMultiplyFunction();
+ $divide = $this->getDivideFunction();
+
+ $mul_div = $mult->apply($divide);
+ $res = $mul_div->apply(6)->apply(3)->apply(5)->get();
+
+ $this->assertEquals(10,$res);
+ }
+}
\ No newline at end of file