Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

UI: cleanup magic for signal-mechanism #578

Merged
merged 10 commits into from
Jul 25, 2017
13 changes: 12 additions & 1 deletion src/UI/Component/JavaScriptBindable.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,21 @@ interface JavaScriptBindable {
* });
*
* @param \Closure $binder
* @param self
* @return self
*/
public function withOnLoadCode(\Closure $binder);

/**
* Add some onload-code to the component instead of replacing the existing one.
*
* Must work like getOnLoadCode was called and the result of the existing binder
* (if any) and the result of the new binder are concatenated in a new binder.
*
* @param \Closure $binder
* @return self
*/
public function withAdditionalOnLoadCode(\Closure $binder);

/**
* Get the currently bound on load code.
*
Expand Down
4 changes: 2 additions & 2 deletions src/UI/Component/Triggerable.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
*
* @package ILIAS\UI\Component
*/
interface Triggerable {
interface Triggerable extends JavaScriptBindable {

/**
* Get a component like this but reset (regenerate) its signals.
Expand All @@ -21,4 +21,4 @@ interface Triggerable {
*/
public function withResetSignals();

}
}
5 changes: 2 additions & 3 deletions src/UI/Component/Triggerer.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
*
* @package ILIAS\UI\Component
*/
interface Triggerer {
interface Triggerer extends JavaScriptBindable {

/**
* Get a component like this but reset any triggered signals of other components
Expand All @@ -26,5 +26,4 @@ public function withResetTriggeredSignals();
* @return TriggeredSignalInterface[]
*/
public function getTriggeredSignals();

}
}
10 changes: 0 additions & 10 deletions src/UI/Implementation/Component/Button/Renderer.php
Original file line number Diff line number Diff line change
Expand Up @@ -101,11 +101,6 @@ protected function renderClose($component) {

protected function maybeRenderId(Component\Component $component, $tpl) {
$id = $this->bindJavaScript($component);
// Check if the button is acting as triggerer
if ($component instanceof Component\Triggerer && count($component->getTriggeredSignals())) {
$id = ($id === null) ? $this->createId() : $id;
$this->triggerRegisteredSignals($component, $id);
}
if ($id !== null) {
$tpl->setCurrentBlock("with_id");
$tpl->setVariable("ID", $id);
Expand All @@ -128,11 +123,6 @@ protected function renderMonth(Component\Button\Month $component, RendererInterf

$id = $this->bindJavaScript($component);

// Check if the button is acting as triggerer
if ($component instanceof Component\Triggerer && count($component->getTriggeredSignals())) {
$id = ($id === null) ? $this->createId() : $id;
$this->triggerRegisteredSignals($component, $id);
}
if ($id !== null) {
$tpl->setCurrentBlock("with_id");
$tpl->setVariable("ID", $id);
Expand Down
5 changes: 0 additions & 5 deletions src/UI/Implementation/Component/Dropdown/Renderer.php
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,6 @@ protected function renderItems($items, $tpl, $default_renderer)

protected function maybeRenderId(Component\Component $component, $tpl, $block, $template_var) {
$id = $this->bindJavaScript($component);
// Check if the component is acting as triggerer
if ($component instanceof Component\Triggerer && count($component->getTriggeredSignals())) {
$id = ($id === null) ? $this->createId() : $id;
$this->triggerRegisteredSignals($component, $id);
}
if ($id !== null) {
$tpl->setCurrentBlock($block);
$tpl->setVariable($template_var, $id);
Expand Down
4 changes: 0 additions & 4 deletions src/UI/Implementation/Component/Glyph/Renderer.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,6 @@ public function render(Component\Component $component, RendererInterface $defaul
$id = $this->bindJavaScript($component);

$tpl->touchBlock($component->getType());
if ($component instanceof Component\Triggerer && count($component->getTriggeredSignals())) {
$id = ($id === null) ? $this->createId() : $id;
$this->triggerRegisteredSignals($component, $id);
}

if ($id !== null) {
$tpl->setCurrentBlock("with_id");
Expand Down
15 changes: 15 additions & 0 deletions src/UI/Implementation/Component/JavaScriptBindable.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,21 @@ public function withOnLoadCode(\Closure $binder) {
return $clone;
}

/**
* @see \ILIAS\UI\Component\JavaScriptBindable::withAdditionalOnLoadCode
*/
public function withAdditionalOnLoadCode(\Closure $binder) {
$current_binder = $this->getOnLoadCode();
if ($current_binder === null) {
return $this->withOnLoadCode($binder);
}

$this->checkBinder($binder);
return $this->withOnLoadCode(function($id) use ($current_binder, $binder) {
return $current_binder($id)."\n".$binder($id);
});
}

/**
* @see \ILIAS\UI\Component\JavaScriptBindable::getOnLoadCode
*/
Expand Down
49 changes: 31 additions & 18 deletions src/UI/Implementation/Component/Modal/Renderer.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,27 +47,43 @@ public function registerResources(ResourceRegistry $registry) {
* @param Component\Modal\Modal $modal
* @param string $id
*/
protected function registerSignals(Component\Modal\Modal $modal, $id) {
protected function registerSignals(Component\Modal\Modal $modal) {
$show = $modal->getShowSignal();
$close = $modal->getCloseSignal();
$js = $this->getJavascriptBinding();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe explain in the comment of this function why this pattern here:

$js = $this->getJavascriptBinding();
$js->addOnLoadCode("
 			$(document).on('{$show}', function() { il.UI.modal.showModal('{$id}', {$options}); return false; });
 			$(document).on('{$close}', function() { il.UI.modal.closeModal('{$id}'); return false; });"
);

Is bad and should not be used and refer to this pattern:

return $modal->withAdditionalOnLoadCode(function($id) use (...) {
			return ...
});

To be used instead.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There you go.

$options = json_encode(array(
'ajaxRenderUrl' => $modal->getAsyncRenderUrl(),
'keyboard' => $modal->getCloseWithKeyboard(),
));
$js->addOnLoadCode("
$(document).on('{$show}', function() { il.UI.modal.showModal('{$id}', {$options}); return false; });
$(document).on('{$close}', function() { il.UI.modal.closeModal('{$id}'); return false; });"
);
// ATTENTION, ATTENTION:
// with(Additional)OnLoadCode opens a wormhole into the future, where some unspecified
// entity magically created an id for the component that can be used to refer to it
// via javascript.
// This replaced a pattern, where an id was created manually and the java script
// code was manually inserted to the (now internal) js-binding of the
// AbstractComponentRenderer. (see commit 192144fd1f0e040cadc0149c3dc15fbc4b67858e).
// The wormhole solution is considered superior over the manual creation of ids because:
// * withAdditionalOnLoadCode introduces no new principles to the UI framework but reuses
// an existing one
// * withAdditionalOnLoadCode does not require it to expose internals (js-binding) from
// the AbstractComponentRenderer and thus does have less coupling
// * withAdditionalOnLoadCode allows the framework to decide, when ids are actually
// created
// * since withAdditionalOnLoadCode refers to some yet unknown future, it disencourages
// tempering with the id _here_.
return $modal->withAdditionalOnLoadCode(function($id) use ($show, $close, $options) {
return
"$(document).on('{$show}', function() { il.UI.modal.showModal('{$id}', {$options}); return false; });".
"$(document).on('{$close}', function() { il.UI.modal.closeModal('{$id}'); return false; });";
});
}

/**
* @param Component\Modal\Modal $modal
* @return string
*/
protected function renderAsync(Component\Modal\Modal $modal) {
$id = $this->createId();
$this->registerSignals($modal, $id);
$modal = $this->registerSignals($modal);
$id = $this->bindJavaScript($modal);
return "<span id='{$id}'></span>";
}

Expand All @@ -79,9 +95,8 @@ protected function renderAsync(Component\Modal\Modal $modal) {
*/
protected function renderInterruptive(Component\Modal\Interruptive $modal, RendererInterface $default_renderer) {
$tpl = $this->getTemplate('tpl.interruptive.html', true, true);
$id = $this->createId();
$this->registerSignals($modal, $id);
$this->triggerRegisteredSignals($modal, $id);
$modal = $this->registerSignals($modal);
$id = $this->bindJavaScript($modal);
$tpl->setVariable('ID', $id);
$tpl->setVariable('FORM_ACTION', $modal->getFormAction());
$tpl->setVariable('TITLE', $modal->getTitle());
Expand Down Expand Up @@ -113,9 +128,8 @@ protected function renderInterruptive(Component\Modal\Interruptive $modal, Rende
*/
protected function renderRoundTrip(Component\Modal\RoundTrip $modal, RendererInterface $default_renderer) {
$tpl = $this->getTemplate('tpl.roundtrip.html', true, true);
$id = $this->createId();
$this->registerSignals($modal, $id);
$this->triggerRegisteredSignals($modal, $id);
$modal = $this->registerSignals($modal);
$id = $this->bindJavaScript($modal);
$tpl->setVariable('ID', $id);
$tpl->setVariable('TITLE', $modal->getTitle());
foreach ($modal->getContent() as $content) {
Expand All @@ -141,11 +155,10 @@ protected function renderRoundTrip(Component\Modal\RoundTrip $modal, RendererInt
*/
protected function renderLightbox(Component\Modal\Lightbox $modal, RendererInterface $default_renderer) {
$tpl = $this->getTemplate('tpl.lightbox.html', true, true);
$id = $this->createId();
$this->registerSignals($modal, $id);
$this->triggerRegisteredSignals($modal, $id);
$modal = $this->registerSignals($modal);
$id = $this->bindJavaScript($modal);
$tpl->setVariable('ID', $id);
$id_carousel = $this->createId();
$id_carousel = "{$id}_carousel";
$pages = $modal->getPages();
$tpl->setVariable('TITLE', $pages[0]->getTitle());
$tpl->setVariable('ID_CAROUSEL', $id_carousel);
Expand Down
5 changes: 4 additions & 1 deletion src/UI/Implementation/Component/Popover/Popover.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use \ILIAS\UI\Component;
use ILIAS\UI\Component\Signal;
use ILIAS\UI\Implementation\Component\ComponentHelper;
use ILIAS\UI\Implementation\Component\JavaScriptBindable;
use ILIAS\UI\Implementation\Component\SignalGeneratorInterface;

/**
Expand All @@ -16,6 +17,8 @@
abstract class Popover implements Component\Popover\Popover {

use ComponentHelper;
use JavaScriptBindable;

/**
* @var string
*/
Expand Down Expand Up @@ -155,4 +158,4 @@ protected function initSignals() {
$this->show_signal = $this->signal_generator->create();
$this->replace_content_signal = $this->signal_generator->create("ILIAS\\UI\\Implementation\\Component\\Popover\\ReplaceContentSignal");
}
}
}
42 changes: 26 additions & 16 deletions src/UI/Implementation/Component/Popover/Renderer.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,39 +23,49 @@ public function render(Component\Component $component, RendererInterface $defaul
$tpl = $this->getTemplate('tpl.popover.html', true, true);
$tpl->setVariable('FORCE_RENDERING', '');
/** @var Component\Popover\Popover $component */

$options = array(
'title' => $this->escape($component->getTitle()),
'placement' => $component->getPosition(),
'multi' => true,
'template' => str_replace('"', '\"', $tpl->get()),
);
// Check if the content is rendered async or via DOM
$content_id = $this->createId();
if ($component->getAsyncContentUrl()) {

$is_async = $component->getAsyncContentUrl();
if ($is_async) {
$options['type'] = 'async';
$options['url'] = $component->getAsyncContentUrl();
} else {
$options['url'] = "#{$content_id}";
}
$options = json_encode($options);

$show = $component->getShowSignal();
$this->getJavascriptBinding()->addOnLoadCode("
$(document).on('{$show}', function(event, signalData) {
il.UI.popover.showFromSignal(signalData, JSON.parse('{$options}'));
});");
$replace = $component->getReplaceContentSignal();
$this->getJavascriptBinding()->addOnLoadCode("
$(document).on('{$replace}', function(event, signalData) {
il.UI.popover.replaceContentFromSignal('{$show}', signalData);
});");

$component = $component->withAdditionalOnLoadCode(function($id) use ($options, $show, $replace, $is_async) {
if (!$is_async) {
$options["url"] = "#{$id}";
}
$options = json_encode($options);

return
"$(document).on('{$show}', function(event, signalData) {
il.UI.popover.showFromSignal(signalData, JSON.parse('{$options}'));
});".
"$(document).on('{$replace}', function(event, signalData) {
il.UI.popover.replaceContentFromSignal('{$show}', signalData);
});";
});

$id = $this->bindJavaScript($component);

if ($component->getAsyncContentUrl()) {
return '';
}

if ($component instanceof Component\Popover\Standard) {
return $this->renderStandardPopover($component, $default_renderer, $content_id);
return $this->renderStandardPopover($component, $default_renderer, $id);
} else {
if ($component instanceof Component\Popover\Listing) {
return $this->renderListingPopover($component, $default_renderer, $content_id);
return $this->renderListingPopover($component, $default_renderer, $id);
}
}

Expand Down
7 changes: 1 addition & 6 deletions src/UI/Implementation/Component/ViewControl/Renderer.php
Original file line number Diff line number Diff line change
Expand Up @@ -105,11 +105,6 @@ protected function renderSectionButton(Component\Button\Button $component, $tpl,

protected function maybeRenderId(Component\Component $component, $tpl, $block, $template_var) {
$id = $this->bindJavaScript($component);
// Check if the component is acting as triggerer
if ($component instanceof Component\Triggerer && count($component->getTriggeredSignals())) {
$id = ($id === null) ? $this->createId() : $id;
$this->triggerRegisteredSignals($component, $id);
}
if ($id !== null) {
$tpl->setCurrentBlock($block);
$tpl->setVariable($template_var, $id);
Expand All @@ -128,4 +123,4 @@ protected function getComponentInterfaceName() {

}

}
}
Loading