1<?php 2 3/* Copyright (c) 2018 Thomas Famula <famula@leifos.de> Extended GPL, see docs/LICENSE */ 4 5namespace ILIAS\UI\Implementation\Component\Input\Container\Filter; 6 7use ILIAS\UI\Component; 8use ILIAS\UI\Component\Input\Container\Filter; 9use ILIAS\UI\Implementation\Component\SignalGenerator; 10use ILIAS\UI\Implementation\Render\AbstractComponentRenderer; 11use ILIAS\UI\Implementation\Render\Template; 12use ILIAS\UI\Renderer as RendererInterface; 13 14class Renderer extends AbstractComponentRenderer 15{ 16 17 /** 18 * @inheritdoc 19 */ 20 public function render(Component\Component $component, RendererInterface $default_renderer) 21 { 22 $this->checkComponent($component); 23 24 if ($component instanceof Filter\Standard) { 25 return $this->renderStandard($component, $default_renderer); 26 } 27 28 throw new \LogicException("Cannot render: " . get_class($component)); 29 } 30 31 /** 32 * Render standard filter 33 * 34 * @param Filter\Standard $component 35 * @param RendererInterface $default_renderer 36 * @return Template string 37 */ 38 protected function renderStandard(Filter\Standard $component, RendererInterface $default_renderer) 39 { 40 $tpl = $this->getTemplate("tpl.standard_filter.html", true, true); 41 42 // JavaScript 43 $component = $this->registerSignals($component); 44 $id = $this->bindJavaScript($component); 45 $tpl->setVariable('ID_FILTER', $id); 46 47 // render expand and collapse 48 $this->renderExpandAndCollapse($tpl, $component, $default_renderer); 49 50 // render apply and reset buttons 51 $this->renderApplyAndReset($tpl, $component, $default_renderer); 52 53 // render toggle button 54 $this->renderToggleButton($tpl, $component, $default_renderer); 55 56 // render inputs 57 $this->renderInputs($tpl, $component, $default_renderer); 58 59 return $tpl->get(); 60 } 61 62 /** 63 * @param Filter\Filter $filter 64 * @return Component\JavaScriptBindable 65 */ 66 protected function registerSignals(Filter\Filter $filter) 67 { 68 $update = $filter->getUpdateSignal(); 69 return $filter->withAdditionalOnLoadCode(function ($id) use ($update) { 70 $code = 71 "$(document).on('{$update}', function(event, signalData) { il.UI.filter.onInputUpdate(event, signalData, '{$id}'); return false; });"; 72 return $code; 73 }); 74 } 75 76 /** 77 * Render expand/collapse section 78 * 79 * @param Template $tpl 80 * @param Filter\Standard $component 81 * @param RendererInterface $default_renderer 82 */ 83 protected function renderExpandAndCollapse(Template $tpl, Filter\Standard $component, RendererInterface $default_renderer) 84 { 85 $f = $this->getUIFactory(); 86 87 $tpl->setCurrentBlock("action"); 88 $tpl->setVariable("ACTION_NAME", "expand"); 89 $tpl->setVariable("ACTION", $component->getExpandAction()); 90 $tpl->parseCurrentBlock(); 91 92 $opener_expand = $f->button()->bulky($f->symbol()->glyph()->expand(), $this->txt("filter"), "") 93 ->withAdditionalOnLoadCode(function ($id) { 94 $code = "$('#$id').on('click', function(event) { 95 il.UI.filter.onAjaxCmd(event, '$id', 'expand'); 96 event.preventDefault(); 97 });"; 98 return $code; 99 }); 100 101 $tpl->setCurrentBlock("action"); 102 $tpl->setVariable("ACTION_NAME", "collapse"); 103 $tpl->setVariable("ACTION", $component->getCollapseAction()); 104 $tpl->parseCurrentBlock(); 105 106 $opener_collapse = $f->button()->bulky($f->symbol()->glyph()->collapse(), $this->txt("filter"), "") 107 ->withAdditionalOnLoadCode(function ($id) { 108 $code = "$('#$id').on('click', function(event) { 109 il.UI.filter.onAjaxCmd(event, '$id', 'collapse'); 110 event.preventDefault(); 111 });"; 112 return $code; 113 }); 114 115 if ($component->isExpanded() == false) { 116 $opener = [$opener_collapse, $opener_expand]; 117 $tpl->setVariable("OPENER", $default_renderer->render($opener)); 118 $tpl->setVariable("ARIA_EXPANDED", "'false'"); 119 $tpl->setVariable("INPUTS_ACTIVE_EXPANDED", "in"); 120 } else { 121 $opener = [$opener_expand, $opener_collapse]; 122 $tpl->setVariable("OPENER", $default_renderer->render($opener)); 123 $tpl->setVariable("ARIA_EXPANDED", "'true'"); 124 $tpl->setVariable("INPUTS_EXPANDED", "in"); 125 } 126 } 127 128 /** 129 * Render apply and reset 130 * 131 * @param Template $tpl 132 * @param Filter\Standard $component 133 * @param RendererInterface $default_renderer 134 */ 135 protected function renderApplyAndReset(Template $tpl, Filter\Standard $component, RendererInterface $default_renderer) 136 { 137 $f = $this->getUIFactory(); 138 139 $tpl->setCurrentBlock("action"); 140 $tpl->setVariable("ACTION_NAME", "apply"); 141 $tpl->setVariable("ACTION", $component->getApplyAction()); 142 $tpl->parseCurrentBlock(); 143 144 // render apply and reset buttons 145 $apply = $f->button()->bulky($f->symbol()->glyph()->apply(), $this->txt("apply"), ""); 146 147 if (!$component->isActivated()) { 148 $apply = $apply->withUnavailableAction(); 149 $reset = $f->button()->bulky($f->symbol()->glyph()->reset(), $this->txt("reset"), "") 150 ->withUnavailableAction(); 151 } else { 152 $apply = $apply->withOnLoadCode(function ($id) { 153 $code = "$('#$id').on('click', function(event) { 154 il.UI.filter.onCmd(event, '$id', 'apply'); 155 return false; // stop event propagation 156 }); 157 $('#$id').closest('.il-filter').find(':text').on('keypress', function(ev) { 158 if (typeof ev != 'undefined' && typeof ev.keyCode != 'undefined' && ev.keyCode == 13) { 159 il.UI.filter.onCmd(event, '$id', 'apply'); 160 return false; // stop event propagation 161 } 162 }); 163 "; 164 return $code; 165 }); 166 167 $reset = $f->button()->bulky($f->symbol()->glyph()->reset(), $this->txt("reset"), $component->getResetAction()); 168 } 169 $tpl->setVariable("APPLY", $default_renderer->render($apply)); 170 $tpl->setVariable("RESET", $default_renderer->render($reset)); 171 } 172 173 /** 174 * Render toggle button 175 * 176 * @param Template $tpl 177 * @param Filter\Standard $component 178 * @param RendererInterface $default_renderer 179 */ 180 protected function renderToggleButton(Template $tpl, Filter\Standard $component, RendererInterface $default_renderer) 181 { 182 $f = $this->getUIFactory(); 183 184 $tpl->setCurrentBlock("action"); 185 $tpl->setVariable("ACTION_NAME", "toggleOn"); 186 $tpl->setVariable("ACTION", $component->getToggleOnAction()); 187 $tpl->parseCurrentBlock(); 188 189 $component->getToggleOnAction(); 190 $signal_generator = new SignalGenerator(); 191 $toggle_on_signal = $signal_generator->create(); 192 $toggle_on_action = $component->getToggleOnAction(); 193 $toggle = $f->button()->toggle("", $toggle_on_signal, $component->getToggleOffAction(), $component->isActivated()) 194 ->withAdditionalOnLoadCode(function ($id) use ($toggle_on_signal, $toggle_on_action) { 195 $code = "$(document).on('{$toggle_on_signal}',function(event) { 196 il.UI.filter.onCmd(event, '$id', 'toggleOn'); 197 return false; // stop event propagation 198 });"; 199 return $code; 200 }); 201 202 $tpl->setVariable("TOGGLE", $default_renderer->render($toggle)); 203 } 204 205 /** 206 * Render inputs 207 * 208 * @param Template $tpl 209 * @param Filter\Standard $component 210 * @param RendererInterface $default_renderer 211 */ 212 protected function renderInputs(Template $tpl, Filter\Standard $component, RendererInterface $default_renderer) 213 { 214 // pass information on what inputs should be initially rendered 215 $is_input_rendered = $component->isInputRendered(); 216 foreach ($component->getInputs() as $k => $input) { 217 $is_rendered = current($is_input_rendered); 218 $tpl->setCurrentBlock("status"); 219 $tpl->setVariable("FIELD", $k); 220 $tpl->setVariable("VALUE", (int) $is_rendered); 221 $tpl->parseCurrentBlock(); 222 next($is_input_rendered); 223 } 224 225 // render inputs 226 $input_group = $component->getInputGroup(); 227 if ($component->isActivated()) { 228 for ($i = 1; $i <= count($component->getInputs()); $i++) { 229 $tpl->setCurrentBlock("active_inputs"); 230 $tpl->setVariable("ID", $i); 231 $tpl->parseCurrentBlock(); 232 } 233 if (count($component->getInputs()) > 0) { 234 $tpl->setCurrentBlock("active_inputs_section"); 235 $tpl->parseCurrentBlock(); 236 } 237 $tpl->touchBlock("enabled"); 238 } else { 239 $tpl->touchBlock("disabled"); 240 $input_group = $input_group->withDisabled(true); 241 } 242 243 $input_group = $input_group->withOnUpdate($component->getUpdateSignal()); 244 245 $renderer = $default_renderer->withAdditionalContext($component); 246 $tpl->setVariable("INPUTS", $renderer->render($input_group)); 247 } 248 249 250 /** 251 * @inheritdoc 252 */ 253 protected function getComponentInterfaceName() 254 { 255 return array( 256 Filter\Standard::class, 257 ); 258 } 259} 260