1<?php 2namespace ILIAS\UI\Implementation\Component\Modal; 3 4use ILIAS\UI\Component\Modal\LightboxDescriptionEnabledPage; 5use ILIAS\UI\Implementation\Render\AbstractComponentRenderer; 6use ILIAS\UI\Implementation\Render\ResourceRegistry; 7use ILIAS\UI\Renderer as RendererInterface; 8use ILIAS\UI\Component; 9 10/** 11 * @author Stefan Wanzenried <sw@studer-raimann.ch> 12 */ 13class Renderer extends AbstractComponentRenderer 14{ 15 16 /** 17 * @inheritdoc 18 */ 19 public function render(Component\Component $component, RendererInterface $default_renderer) 20 { 21 $this->checkComponent($component); 22 23 // If the modal is rendered async, we just create a fake container which will be 24 // replaced by the modal upon successful ajax request 25 /** @var Modal $component */ 26 if ($component->getAsyncRenderUrl()) { 27 return $this->renderAsync($component); 28 } 29 30 if ($component instanceof Component\Modal\Interruptive) { 31 return $this->renderInterruptive($component, $default_renderer); 32 } elseif ($component instanceof Component\Modal\RoundTrip) { 33 return $this->renderRoundTrip($component, $default_renderer); 34 } elseif ($component instanceof Component\Modal\Lightbox) { 35 return $this->renderLightbox($component, $default_renderer); 36 } 37 return ''; 38 } 39 40 /** 41 * @inheritdoc 42 */ 43 public function registerResources(ResourceRegistry $registry) 44 { 45 parent::registerResources($registry); 46 $registry->register('./src/UI/templates/js/Modal/modal.js'); 47 } 48 49 50 /** 51 * @param Component\Modal\Modal $modal 52 * @param string $id 53 */ 54 protected function registerSignals(Component\Modal\Modal $modal) 55 { 56 $show = $modal->getShowSignal(); 57 $close = $modal->getCloseSignal(); 58 59 $replace = ""; 60 if ($modal instanceof Component\Modal\RoundTrip) { 61 $replace = $modal->getReplaceSignal(); 62 } 63 64 $options = array( 65 'ajaxRenderUrl' => $modal->getAsyncRenderUrl(), 66 'keyboard' => $modal->getCloseWithKeyboard() 67 ); 68 // ATTENTION, ATTENTION: 69 // with(Additional)OnLoadCode opens a wormhole into the future, where some unspecified 70 // entity magically created an id for the component that can be used to refer to it 71 // via javascript. 72 // This replaced a pattern, where an id was created manually and the java script 73 // code was manually inserted to the (now internal) js-binding of the 74 // AbstractComponentRenderer. (see commit 192144fd1f0e040cadc0149c3dc15fbc4b67858e). 75 // The wormhole solution is considered superior over the manual creation of ids because: 76 // * withAdditionalOnLoadCode introduces no new principles to the UI framework but reuses 77 // an existing one 78 // * withAdditionalOnLoadCode does not require it to expose internals (js-binding) from 79 // the AbstractComponentRenderer and thus does have less coupling 80 // * withAdditionalOnLoadCode allows the framework to decide, when ids are actually 81 // created 82 // * since withAdditionalOnLoadCode refers to some yet unknown future, it disencourages 83 // tempering with the id _here_. 84 return $modal->withAdditionalOnLoadCode(function ($id) use ($show, $close, $options, $replace) { 85 $options["url"] = "#{$id}"; 86 $options = json_encode($options); 87 $code = 88 "$(document).on('{$show}', function(event, signalData) { il.UI.modal.showModal('{$id}', {$options}, signalData); return false; });" . 89 "$(document).on('{$close}', function() { il.UI.modal.closeModal('{$id}'); return false; });"; 90 if ($replace != "") { 91 $code .= "$(document).on('{$replace}', function(event, signalData) { il.UI.modal.replaceFromSignal('{$id}', signalData);});"; 92 } 93 return $code; 94 }); 95 } 96 97 /** 98 * @param Component\Modal\Modal $modal 99 * @return string 100 */ 101 protected function renderAsync(Component\Modal\Modal $modal) 102 { 103 $modal = $this->registerSignals($modal); 104 $id = $this->bindJavaScript($modal); 105 return "<span id='{$id}'></span>"; 106 } 107 108 /** 109 * @param Component\Modal\Interruptive $modal 110 * @param RendererInterface $default_renderer 111 * 112 * @return string 113 */ 114 protected function renderInterruptive(Component\Modal\Interruptive $modal, RendererInterface $default_renderer) 115 { 116 $tpl = $this->getTemplate('tpl.interruptive.html', true, true); 117 $modal = $this->registerSignals($modal); 118 $id = $this->bindJavaScript($modal); 119 $tpl->setVariable('ID', $id); 120 $tpl->setVariable('FORM_ACTION', $modal->getFormAction()); 121 $tpl->setVariable('TITLE', $modal->getTitle()); 122 $tpl->setVariable('MESSAGE', $modal->getMessage()); 123 if (count($modal->getAffectedItems())) { 124 $tpl->setCurrentBlock('with_items'); 125 foreach ($modal->getAffectedItems() as $item) { 126 $tpl->setCurrentBlock('item'); 127 $icon = ($item->getIcon()) ? $default_renderer->render($item->getIcon()) : ''; 128 $desc = ($item->getDescription()) ? '<br>' . $item->getDescription() : ''; 129 $tpl->setVariable('ITEM_ICON', $icon); 130 $tpl->setVariable('ITEM_ID', $item->getId()); 131 $tpl->setVariable('ITEM_TITLE', $item->getTitle()); 132 $tpl->setVariable('ITEM_DESCRIPTION', $desc); 133 $tpl->parseCurrentBlock(); 134 } 135 } 136 $tpl->setVariable('ACTION_BUTTON_LABEL', $this->txt($modal->getActionButtonLabel())); 137 $tpl->setVariable('CANCEL_BUTTON_LABEL', $this->txt($modal->getCancelButtonLabel())); 138 return $tpl->get(); 139 } 140 141 142 /** 143 * @param Component\Modal\RoundTrip $modal 144 * @param RendererInterface $default_renderer 145 * 146 * @return string 147 */ 148 protected function renderRoundTrip(Component\Modal\RoundTrip $modal, RendererInterface $default_renderer) 149 { 150 $tpl = $this->getTemplate('tpl.roundtrip.html', true, true); 151 $modal = $this->registerSignals($modal); 152 $id = $this->bindJavaScript($modal); 153 $tpl->setVariable('ID', $id); 154 $tpl->setVariable('TITLE', $modal->getTitle()); 155 foreach ($modal->getContent() as $content) { 156 $tpl->setCurrentBlock('with_content'); 157 $tpl->setVariable('CONTENT', $default_renderer->render($content)); 158 $tpl->parseCurrentBlock(); 159 } 160 foreach ($modal->getActionButtons() as $button) { 161 $tpl->setCurrentBlock('with_buttons'); 162 $tpl->setVariable('BUTTON', $default_renderer->render($button)); 163 $tpl->parseCurrentBlock(); 164 } 165 $tpl->setVariable('CANCEL_BUTTON_LABEL', $this->txt($modal->getCancelButtonLabel())); 166 return $tpl->get(); 167 } 168 169 170 /** 171 * @param Component\Modal\Lightbox $modal 172 * @param RendererInterface $default_renderer 173 * 174 * @return string 175 */ 176 protected function renderLightbox(Component\Modal\Lightbox $modal, RendererInterface $default_renderer) 177 { 178 $tpl = $this->getTemplate('tpl.lightbox.html', true, true); 179 $modal = $this->registerSignals($modal); 180 $id = $this->bindJavaScript($modal); 181 $tpl->setVariable('ID', $id); 182 $id_carousel = "{$id}_carousel"; 183 $pages = $modal->getPages(); 184 $tpl->setVariable('TITLE', $pages[0]->getTitle()); 185 $tpl->setVariable('ID_CAROUSEL', $id_carousel); 186 if (count($pages) > 1) { 187 $tpl->setCurrentBlock('has_indicators'); 188 foreach ($pages as $index => $page) { 189 $tpl->setCurrentBlock('indicators'); 190 $tpl->setVariable('INDEX', $index); 191 $tpl->setVariable('CLASS_ACTIVE', ($index == 0) ? 'active' : ''); 192 $tpl->setVariable('ID_CAROUSEL2', $id_carousel); 193 $tpl->parseCurrentBlock(); 194 } 195 } 196 foreach ($pages as $i => $page) { 197 if ($page instanceof LightboxTextPage) { 198 $tpl->setCurrentBlock('pages'); 199 $tpl->touchBlock('page_type_text'); 200 $tpl->parseCurrentBlock(); 201 } 202 $tpl->setCurrentBlock('pages'); 203 $tpl->setVariable('CLASS_ACTIVE', ($i == 0) ? ' active' : ''); 204 $tpl->setVariable('TITLE2', htmlentities($page->getTitle(), ENT_QUOTES, 'UTF-8')); 205 $tpl->setVariable('CONTENT', $default_renderer->render($page->getComponent())); 206 if ($page instanceof LightboxDescriptionEnabledPage) { 207 $tpl->setVariable('DESCRIPTION', $page->getDescription()); 208 } 209 $tpl->parseCurrentBlock(); 210 } 211 if (count($pages) > 1) { 212 $tpl->setCurrentBlock('controls'); 213 $tpl->setVariable('ID_CAROUSEL3', $id_carousel); 214 $tpl->parseCurrentBlock(); 215 } 216 $tpl->setVariable('ID_CAROUSEL4', $id_carousel); 217 return $tpl->get(); 218 } 219 220 221 /** 222 * @inheritdoc 223 */ 224 protected function getComponentInterfaceName() 225 { 226 return array( 227 Component\Modal\Interruptive::class, 228 Component\Modal\RoundTrip::class, 229 Component\Modal\Lightbox::class, 230 ); 231 } 232} 233