ILIAS  release_9 Revision v9.13-25-g2c18ec4c24f
AbstractComponentRenderer.php
Go to the documentation of this file.
1 <?php
2 
19 declare(strict_types=1);
20 
22 
29 use ILIAS\UI\Help;
30 use ilLanguage;
32 use LogicException;
34 
43 {
44  private static array $component_storage;
45 
46  final public function __construct(
47  private Factory $ui_factory,
48  private TemplateFactory $tpl_factory,
49  private ilLanguage $lng,
50  private JavaScriptBinding $js_binding,
52  private ImagePathResolver $image_path_resolver,
53  private DataFactory $data_factory,
54  private HelpTextRetriever $help_text_retriever,
55  private UploadLimitResolver $upload_limit_resolver,
56  ) {
57  }
58 
62  public function registerResources(ResourceRegistry $registry): void
63  {
64  $registry->register('./src/UI/templates/js/Core/dist/core.js');
65  }
66 
72  final protected function getUIFactory(): Factory
73  {
74  return $this->ui_factory;
75  }
76 
77  final protected function getDataFactory(): DataFactory
78  {
79  return $this->data_factory;
80  }
81 
82  final protected function getRefinery(): \ILIAS\Refinery\Factory
83  {
84  return $this->refinery;
85  }
86 
87  final protected function getUploadLimitResolver(): UploadLimitResolver
88  {
89  return $this->upload_limit_resolver;
90  }
91 
95  final public function txt(string $id): string
96  {
97  return $this->lng->txt($id);
98  }
99 
104  final public function toJS($key): void
105  {
106  $this->lng->toJS($key);
107  }
108 
112  public function getLangKey(): string
113  {
114  return $this->lng->getLangKey();
115  }
116 
117  final protected function getJavascriptBinding(): JavaScriptBinding
118  {
119  return $this->js_binding;
120  }
121 
130  final protected function getTemplate(string $name, bool $purge_unfilled_vars, bool $purge_unused_blocks): Template
131  {
132  $path = $this->getTemplatePath($name);
133  return $this->getTemplateRaw($path, $purge_unfilled_vars, $purge_unused_blocks);
134  }
135 
139  protected function getTemplatePath(string $name): string
140  {
141  $component = $this->getMyComponent();
142  return "src/UI/templates/default/$component/$name";
143  }
144 
148  private function getTemplateRaw(string $path, bool $purge_unfilled_vars, bool $purge_unused_blocks): Template
149  {
150  return $this->tpl_factory->getTemplate($path, $purge_unfilled_vars, $purge_unused_blocks);
151  }
152 
159  final protected function bindJavaScript(JavaScriptBindable $component): ?string
160  {
161  if ($component instanceof Triggerer) {
162  $component = $this->addTriggererOnLoadCode($component);
163  }
164  return $this->bindOnloadCode($component);
165  }
166 
179  final protected function createId(): string
180  {
181  return $this->js_binding->createId();
182  }
183 
187  private function bindOnloadCode(JavaScriptBindable $component): ?string
188  {
189  $binder = $component->getOnLoadCode();
190  if ($binder === null) {
191  return null;
192  }
193 
194  $id = $this->js_binding->createId();
195  $on_load_code = $binder($id);
196  if (!is_string($on_load_code)) {
197  throw new LogicException(
198  "Expected JavaScript binder to return string" .
199  " (used component: " . get_class($component) . ")"
200  );
201  }
202  $this->js_binding->addOnLoadCode($on_load_code);
203  return $id;
204  }
205 
210  {
211  $triggered_signals = $triggerer->getTriggeredSignals();
212  if (count($triggered_signals) == 0) {
213  return $triggerer;
214  }
215  return $triggerer->withAdditionalOnLoadCode(function ($id) use ($triggered_signals): string {
216  $code = "";
217  foreach ($triggered_signals as $triggered_signal) {
218  $signal = $triggered_signal->getSignal();
219  $event = $triggered_signal->getEvent();
220  $options = json_encode($signal->getOptions());
221  //Note this switch is necessary since $(#...).on('load', ...) could be fired before the binding of the event.
222  //Same seems true fro ready, see: #27456
223  if ($event == 'load' || $event == 'ready') {
224  $code .=
225  "$(document).trigger('$signal',
226  {
227  'id' : '$signal', 'event' : '$event',
228  'triggerer' : $('#$id'),
229  'options' : JSON.parse('$options')
230  }
231  );";
232  } else {
233  $code .=
234  "$('#$id').on('$event', function(event) {
235  $(this).trigger('$signal',
236  {
237  'id' : '$signal', 'event' : '$event',
238  'triggerer' : $(this),
239  'options' : JSON.parse('$options')
240  }
241  );
242  return false;
243  });";
244  }
245  }
246  return $code;
247  });
248  }
249 
256  final protected function checkComponent(Component $component): void
257  {
258  $interfaces = $this->getComponentInterfaceName();
259  if (!is_array($interfaces)) {
260  throw new LogicException(
261  "Expected array, found '" . (string) (null) . "' when rendering."
262  );
263  }
264 
265  foreach ($interfaces as $interface) {
266  if ($component instanceof $interface) {
267  return;
268  }
269  }
270  $ifs = implode(", ", $interfaces);
271  throw new LogicException(
272  "Expected $ifs, found '" . get_class($component) . "' when rendering."
273  );
274  }
275 
283  abstract protected function getComponentInterfaceName(): array;
284 
288  private function getMyComponent()
289  {
290  $class = get_class($this);
291  if (isset(self::$component_storage[$class])) {
292  return self::$component_storage[$class];
293  }
294  $matches = array();
295  // Extract component
296  $re = "%ILIAS\\\\UI\\\\Implementation\\\\Component\\\\(\\w+)\\\\(\\w+)%";
297  preg_match($re, $class, $matches);
298  if (preg_match($re, $class, $matches) !== 1) {
299  throw new LogicException("The Renderer needs to be located in ILIAS\\UI\\Implementation\\Component\\*.");
300  }
301  self::$component_storage[$class] = $matches[1];
302 
303  return self::$component_storage[$class];
304  }
305 
307  {
308  return $this->image_path_resolver;
309  }
310 
311  public function getHelpText(Help\Purpose $purpose, Help\Topic ...$topics): array
312  {
313  return $this->help_text_retriever->getHelpText($purpose, ...$topics);
314  }
315 
316  /*
317  * This is supposed to unify rendering of tooltips over all components.
318  */
320 
321  protected function getTooltipRenderer(): TooltipRenderer
322  {
323  if ($this->tooltip_renderer === null) {
324  $this->tooltip_renderer = new TooltipRenderer(
325  $this,
326  fn($path, $f1, $f2) => $this->getTemplateRaw($path, $f1, $f2)
327  );
328  }
330  }
331 
332  protected function convertSpecialCharacters(string $value): string
333  {
334  return htmlspecialchars($value, ENT_QUOTES | ENT_SUBSTITUTE, 'utf-8');
335  }
336 }
Registry for resources required by rendered output like Javascript or CSS.
getTemplateRaw(string $path, bool $purge_unfilled_vars, bool $purge_unused_blocks)
Get a template from any path.
addTriggererOnLoadCode(Triggerer $triggerer)
Add onload-code for triggerer.
This is just a class that marks a string as a help topic.
Definition: Topic.php:26
checkComponent(Component $component)
Check if a given component fits this renderer and throw if that is not the case. ...
__construct(private Factory $ui_factory, private TemplateFactory $tpl_factory, private ilLanguage $lng, private JavaScriptBinding $js_binding, private \ILIAS\Refinery\Factory $refinery, private ImagePathResolver $image_path_resolver, private DataFactory $data_factory, private HelpTextRetriever $help_text_retriever, private UploadLimitResolver $upload_limit_resolver,)
Class ChatMainBarProvider .
An entity that renders components to a string output.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
trait JavaScriptBindable
Trait for components implementing JavaScriptBindable providing standard implementation.
txt(string $id)
Get a text from the language file.
Some Components need to resolve pathes to image-files.
toJS($key)
Add language var to client side (il.Language)
bindOnloadCode(JavaScriptBindable $component)
Bind the JavaScript onload-code.
$path
Definition: ltiservices.php:32
A purpose describes the intended use for a certain help text.
Definition: Purpose.php:46
This describes a facility that the UI framework can use to retrieve some help text.
getComponentInterfaceName()
Get the name of the component-interface this renderer is supposed to render.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
$lng
This class is supposed to unify rendering of tooltips over all components and should also be usable b...
getTemplate(string $name, bool $purge_unfilled_vars, bool $purge_unused_blocks)
Get template of component this renderer is made for.
getOnLoadCode()
Get the currently bound on load code.
string $key
Consumer key/client ID value.
Definition: System.php:193
Provides methods to interface with javascript.
register(string $name)
Add a dependency.
getTriggeredSignals()
Get all triggered signals of this component.
$id
plugin.php for ilComponentBuildPluginInfoObjectiveTest::testAddPlugins
Definition: plugin.php:23
withAdditionalOnLoadCode(Closure $binder)
Add some onload-code to the component instead of replacing the existing one.
registerResources(ResourceRegistry $registry)
Announce resources this renderer requires.
Interface for a factory that provides templates.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
Definition: Purpose.php:21
getHelpText(Help\Purpose $purpose, Help\Topic ... $topics)
bindJavaScript(JavaScriptBindable $component)
Bind the component to JavaScript.
Refinery Factory $refinery
getTemplatePath(string $name)
Get the path to the template of this component.