예제 #1
0
 /**
  * {@inheritdoc}
  */
 public function process($text, $langcode)
 {
     $response = new FilterProcessResult($text);
     // Use a look ahead to match the capture groups in any order.
     if (preg_match_all('/<p>(?<json>{(?=.*preview_thumbnail\\b)(?=.*settings\\b)(?=.*video_url\\b)(?=.*settings_summary)(.*)})<\\/p>/', $text, $matches)) {
         foreach ($matches['json'] as $delta => $match) {
             // Ensure the JSON string is valid.
             $embed_data = json_decode($match, TRUE);
             if (!is_array($embed_data)) {
                 continue;
             }
             // If the URL can't matched to a provider or the settings are invalid,
             // ignore it.
             $provider = $this->providerManager->loadProviderFromInput($embed_data['video_url']);
             if (!$provider || !$this->validSettings($embed_data['settings'])) {
                 continue;
             }
             $embed_code = $provider->renderEmbedCode($embed_data['settings']['width'], $embed_data['settings']['height'], $embed_data['settings']['autoplay']);
             // Add the container to make the video responsive if it's been
             //configured as such. This usually is attached to field output in the
             // case of a formatter, but a custom container must be used where one is
             // not present.
             if ($embed_data['settings']['responsive']) {
                 $embed_code = ['#type' => 'container', '#attributes' => ['class' => ['video-embed-field-responsive-video']], 'children' => $embed_code];
             }
             // Replace the JSON settings with a video.
             $text = str_replace($matches[0][$delta], $this->renderer->renderRoot($embed_code), $text);
         }
     }
     // Add the required responsive video library and update the response text.
     $response->setProcessedText($text);
     $response->addAttachments(['library' => ['video_embed_field/responsive-video']]);
     return $response;
 }
예제 #2
0
 /**
  * {@inheritdoc}
  */
 public function viewElements(FieldItemListInterface $items, $langcode)
 {
     $element = [];
     $thumbnails = $this->thumbnailFormatter->viewElements($items, $langcode);
     $videos = $this->videoFormatter->viewElements($items, $langcode);
     foreach ($items as $delta => $item) {
         $element[$delta] = ['#type' => 'container', '#attributes' => ['data-video-embed-field-modal' => (string) $this->renderer->renderRoot($videos[$delta]), 'class' => ['video-embed-field-launch-modal']], '#attached' => ['library' => ['video_embed_field/colorbox']], 'children' => $thumbnails[$delta]];
     }
     return $element;
 }
예제 #3
0
 /**
  * @param \Symfony\Component\HttpFoundation\Response $response
  */
 protected function injectToolbar(Response $response)
 {
     $content = $response->getContent();
     $pos = mb_strripos($content, '</body>');
     if (FALSE !== $pos) {
         if ($token = $response->headers->get('X-Debug-Token')) {
             $loader = ['#theme' => 'webprofiler_loader', '#token' => $token, '#profiler_url' => $this->urlGenerator->generate('webprofiler.toolbar', ['profile' => $token])];
             $content = mb_substr($content, 0, $pos) . $this->renderer->renderRoot($loader) . mb_substr($content, $pos);
             $response->setContent($content);
         }
     }
 }
예제 #4
0
 /**
  * {@inheritdoc}
  */
 public function renderResponse(array $main_content, Request $request, RouteMatchInterface $route_match)
 {
     $json = [];
     $json['content'] = (string) $this->renderer->renderRoot($main_content);
     if (!empty($main_content['#title'])) {
         $json['title'] = (string) $main_content['#title'];
     } else {
         $json['title'] = (string) $this->titleResolver->getTitle($request, $route_match->getRouteObject());
     }
     $response = new CacheableJsonResponse($json, 200);
     $response->addCacheableDependency(CacheableMetadata::createFromRenderArray($main_content));
     return $response;
 }
 /**
  * Asserts that a block is built/rendered/cached with expected cacheability.
  *
  * @param string[] $expected_keys
  *   The expected cache keys.
  * @param string[] $expected_contexts
  *   The expected cache contexts.
  * @param string[] $expected_tags
  *   The expected cache tags.
  * @param int $expected_max_age
  *   The expected max-age.
  */
 protected function assertBlockRenderedWithExpectedCacheability(array $expected_keys, array $expected_contexts, array $expected_tags, $expected_max_age)
 {
     $required_cache_contexts = ['languages:' . LanguageInterface::TYPE_INTERFACE, 'theme', 'user.permissions'];
     // Check that the expected cacheability metadata is present in:
     // - the built render array;
     $this->pass('Built render array');
     $build = $this->getBlockRenderArray();
     $this->assertIdentical($expected_keys, $build['#cache']['keys']);
     $this->assertIdentical($expected_contexts, $build['#cache']['contexts']);
     $this->assertIdentical($expected_tags, $build['#cache']['tags']);
     $this->assertIdentical($expected_max_age, $build['#cache']['max-age']);
     $this->assertFalse(isset($build['#create_placeholder']));
     // - the rendered render array;
     $this->pass('Rendered render array');
     $this->renderer->renderRoot($build);
     // - the render cache item.
     $this->pass('Render cache item');
     $final_cache_contexts = Cache::mergeContexts($expected_contexts, $required_cache_contexts);
     $cid = implode(':', $expected_keys) . ':' . implode(':', \Drupal::service('cache_contexts_manager')->convertTokensToKeys($final_cache_contexts)->getKeys());
     $cache_item = $this->container->get('cache.render')->get($cid);
     $this->assertTrue($cache_item, 'The block render element has been cached with the expected cache ID.');
     $this->assertIdentical(Cache::mergeTags($expected_tags, ['rendered']), $cache_item->tags);
     $this->assertIdentical($final_cache_contexts, $cache_item->data['#cache']['contexts']);
     $this->assertIdentical($expected_tags, $cache_item->data['#cache']['tags']);
     $this->assertIdentical($expected_max_age, $cache_item->data['#cache']['max-age']);
     $this->container->get('cache.render')->delete($cid);
 }
예제 #6
0
 /**
  * {@inheritdoc}
  */
 public function viewElements(FieldItemListInterface $items, $langcode)
 {
     $element = [];
     $thumbnails = $this->thumbnailFormatter->viewElements($items, $langcode);
     $videos = $this->videoFormatter->viewElements($items, $langcode);
     foreach ($items as $delta => $item) {
         // Support responsive videos within the colorbox modal.
         if ($this->getSetting('responsive')) {
             $videos[$delta]['#attributes']['class'][] = 'video-embed-field-responsive-modal';
             $videos[$delta]['#attributes']['style'] = sprintf('width:%dpx;', $this->getSetting('modal_max_width'));
         }
         $element[$delta] = ['#type' => 'container', '#attributes' => ['data-video-embed-field-modal' => (string) $this->renderer->renderRoot($videos[$delta]), 'class' => ['video-embed-field-launch-modal']], '#attached' => ['library' => ['video_embed_field/colorbox', 'video_embed_field/responsive-video']], 'children' => $thumbnails[$delta]];
     }
     $this->colorboxAttachment->attach($element);
     return $element;
 }
예제 #7
0
 /**
  * {@inheritdoc}
  */
 public function renderResponse(array $main_content, Request $request, RouteMatchInterface $route_match)
 {
     $response = new AjaxResponse();
     // First render the main content, because it might provide a title.
     $content = $this->renderer->renderRoot($main_content);
     // Attach the library necessary for using the OpenOffCanvasDialogCommand and
     // set the attachments for this Ajax response.
     $main_content['#attached']['library'][] = 'outside_in/drupal.off_canvas';
     $response->setAttachments($main_content['#attached']);
     // If the main content doesn't provide a title, use the title resolver.
     $title = isset($main_content['#title']) ? $main_content['#title'] : $this->titleResolver->getTitle($request, $route_match->getRouteObject());
     // Determine the title: use the title provided by the main content if any,
     // otherwise get it from the routing information.
     $options = $request->request->get('dialogOptions', []);
     $response->addCommand(new OpenOffCanvasDialogCommand($title, $content, $options));
     return $response;
 }
예제 #8
0
 /**
  * Tests block view altering.
  */
 public function testBlockViewBuilderAlter()
 {
     // Establish baseline.
     $build = $this->getBlockRenderArray();
     $this->assertIdentical((string) $this->renderer->renderRoot($build), 'Llamas &gt; unicorns!');
     // Enable the block view alter hook that adds a suffix, for basic testing.
     \Drupal::state()->set('block_test_view_alter_suffix', TRUE);
     Cache::invalidateTags($this->block->getCacheTagsToInvalidate());
     $build = $this->getBlockRenderArray();
     $this->assertTrue(isset($build['#suffix']) && $build['#suffix'] === '<br>Goodbye!', 'A block with content is altered.');
     $this->assertIdentical((string) $this->renderer->renderRoot($build), 'Llamas &gt; unicorns!<br>Goodbye!');
     \Drupal::state()->set('block_test_view_alter_suffix', FALSE);
     // Force a request via GET so we can test the render cache.
     $request = \Drupal::request();
     $request_method = $request->server->get('REQUEST_METHOD');
     $request->setMethod('GET');
     \Drupal::state()->set('block_test.content', NULL);
     Cache::invalidateTags($this->block->getCacheTagsToInvalidate());
     $default_keys = array('entity_view', 'block', 'test_block');
     $default_tags = array('block_view', 'config:block.block.test_block');
     // Advanced: cached block, but an alter hook adds an additional cache key.
     $alter_add_key = $this->randomMachineName();
     \Drupal::state()->set('block_test_view_alter_cache_key', $alter_add_key);
     $cid = 'entity_view:block:test_block:' . $alter_add_key . ':' . implode(':', \Drupal::service('cache_contexts_manager')->convertTokensToKeys(['languages:' . LanguageInterface::TYPE_INTERFACE, 'theme', 'user.permissions'])->getKeys());
     $expected_keys = array_merge($default_keys, array($alter_add_key));
     $build = $this->getBlockRenderArray();
     $this->assertIdentical($expected_keys, $build['#cache']['keys'], 'An altered cacheable block has the expected cache keys.');
     $this->assertIdentical((string) $this->renderer->renderRoot($build), '');
     $cache_entry = $this->container->get('cache.render')->get($cid);
     $this->assertTrue($cache_entry, 'The block render element has been cached with the expected cache ID.');
     $expected_tags = array_merge($default_tags, ['rendered']);
     sort($expected_tags);
     $this->assertIdentical($cache_entry->tags, $expected_tags, 'The block render element has been cached with the expected cache tags.');
     $this->container->get('cache.render')->delete($cid);
     // Advanced: cached block, but an alter hook adds an additional cache tag.
     $alter_add_tag = $this->randomMachineName();
     \Drupal::state()->set('block_test_view_alter_cache_tag', $alter_add_tag);
     $expected_tags = Cache::mergeTags($default_tags, array($alter_add_tag));
     $build = $this->getBlockRenderArray();
     sort($build['#cache']['tags']);
     $this->assertIdentical($expected_tags, $build['#cache']['tags'], 'An altered cacheable block has the expected cache tags.');
     $this->assertIdentical((string) $this->renderer->renderRoot($build), '');
     $cache_entry = $this->container->get('cache.render')->get($cid);
     $this->assertTrue($cache_entry, 'The block render element has been cached with the expected cache ID.');
     $expected_tags = array_merge($default_tags, [$alter_add_tag, 'rendered']);
     sort($expected_tags);
     $this->assertIdentical($cache_entry->tags, $expected_tags, 'The block render element has been cached with the expected cache tags.');
     $this->container->get('cache.render')->delete($cid);
     // Advanced: cached block, but an alter hook adds a #pre_render callback to
     // alter the eventual content.
     \Drupal::state()->set('block_test_view_alter_append_pre_render_prefix', TRUE);
     $build = $this->getBlockRenderArray();
     $this->assertFalse(isset($build['#prefix']), 'The appended #pre_render callback has not yet run before rendering.');
     $this->assertIdentical((string) $this->renderer->renderRoot($build), 'Hiya!<br>');
     $this->assertTrue(isset($build['#prefix']) && $build['#prefix'] === 'Hiya!<br>', 'A cached block without content is altered.');
     // Restore the previous request method.
     $request->setMethod($request_method);
 }
예제 #9
0
 /**
  * Renders an array of assets.
  *
  * @param array $all_assets
  *   An array of all unrendered assets keyed by type.
  *
  * @return array
  *   An array of all rendered assets keyed by type.
  */
 protected function renderAssets(array $all_assets)
 {
     $result = [];
     foreach ($all_assets as $asset_type => $assets) {
         $result[$asset_type] = [];
         foreach ($assets as $asset) {
             $result[$asset_type][] = $this->renderer->renderRoot($asset);
         }
     }
     return $result;
 }
예제 #10
0
 /**
  * Generates representations of a book page and its children.
  *
  * The method delegates the generation of output to helper methods. The method
  * name is derived by prepending 'bookExport' to the camelized form of given
  * output type. For example, a type of 'html' results in a call to the method
  * bookExportHtml().
  *
  * @param string $type
  *   A string encoding the type of output requested. The following types are
  *   currently supported in book module:
  *   - html: Printer-friendly HTML.
  *   Other types may be supported in contributed modules.
  * @param \Drupal\node\NodeInterface $node
  *   The node to export.
  *
  * @return array
  *   A render array representing the node and its children in the book
  *   hierarchy in a format determined by the $type parameter.
  *
  * @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException
  */
 public function bookExport($type, NodeInterface $node)
 {
     $method = 'bookExport' . Container::camelize($type);
     // @todo Convert the custom export functionality to serializer.
     if (!method_exists($this->bookExport, $method)) {
         drupal_set_message(t('Unknown export format.'));
         throw new NotFoundHttpException();
     }
     $exported_book = $this->bookExport->{$method}($node);
     return new Response($this->renderer->renderRoot($exported_book));
 }
예제 #11
0
 /**
  * {@inheritdoc}
  */
 public function execute()
 {
     parent::execute();
     $output = $this->view->render();
     $header = [];
     $header['Content-type'] = $this->getMimeType();
     $response = new CacheableResponse($this->renderer->renderRoot($output), 200);
     $cache_metadata = CacheableMetadata::createFromRenderArray($output);
     $response->addCacheableDependency($cache_metadata);
     return $response;
 }
 /**
  * Renders placeholders (#attached['placeholders']).
  *
  * First, the HTML response object is converted to an equivalent render array,
  * with #markup being set to the response's content and #attached being set to
  * the response's attachments. Among these attachments, there may be
  * placeholders that need to be rendered (replaced).
  *
  * Next, RendererInterface::renderRoot() is called, which renders the
  * placeholders into their final markup.
  *
  * The markup that results from RendererInterface::renderRoot() is now the
  * original HTML response's content, but with the placeholders rendered. We
  * overwrite the existing content in the original HTML response object with
  * this markup. The markup that was rendered for the placeholders may also
  * have attachments (e.g. for CSS/JS assets) itself, and cacheability metadata
  * that indicates what that markup depends on. That metadata is also added to
  * the HTML response object.
  *
  * @param \Drupal\Core\Render\HtmlResponse $response
  *   The HTML response whose placeholders are being replaced.
  *
  * @return \Drupal\Core\Render\HtmlResponse
  *   The updated HTML response, with replaced placeholders.
  *
  * @see \Drupal\Core\Render\Renderer::replacePlaceholders()
  * @see \Drupal\Core\Render\Renderer::renderPlaceholder()
  */
 protected function renderPlaceholders(HtmlResponse $response)
 {
     $build = ['#markup' => Markup::create($response->getContent()), '#attached' => $response->getAttachments()];
     // RendererInterface::renderRoot() renders the $build render array and
     // updates it in place. We don't care about the return value (which is just
     // $build['#markup']), but about the resulting render array.
     // @todo Simplify this when https://www.drupal.org/node/2495001 lands.
     $this->renderer->renderRoot($build);
     // Update the Response object now that the placeholders have been rendered.
     $placeholders_bubbleable_metadata = BubbleableMetadata::createFromRenderArray($build);
     $response->setContent($build['#markup'])->addCacheableDependency($placeholders_bubbleable_metadata)->setAttachments($placeholders_bubbleable_metadata->getAttachments());
     return $response;
 }
예제 #13
0
 /**
  * Renders a field.
  *
  * If the view mode ID is not an Entity Display view mode ID, then the field
  * was rendered using a custom render pipeline (not the Entity/Field API
  * render pipeline).
  *
  * An example could be Views' render pipeline. In that case, the view mode ID
  * would probably contain the View's ID, display and the row index.
  *
  * @param \Drupal\Core\Entity\EntityInterface $entity
  *   The entity being edited.
  * @param string $field_name
  *   The name of the field that is being edited.
  * @param string $langcode
  *   The name of the language for which the field is being edited.
  * @param string $view_mode_id
  *   The view mode the field should be rerendered in. Either an Entity Display
  *   view mode ID, or a custom one. See hook_quickedit_render_field().
  *
  * @return \Drupal\Component\Render\MarkupInterface
  *   Rendered HTML.
  *
  * @see hook_quickedit_render_field()
  */
 protected function renderField(EntityInterface $entity, $field_name, $langcode, $view_mode_id)
 {
     $entity_view_mode_ids = array_keys($this->entityManager()->getViewModes($entity->getEntityTypeId()));
     if (in_array($view_mode_id, $entity_view_mode_ids)) {
         $entity = \Drupal::entityManager()->getTranslationFromContext($entity, $langcode);
         $output = $entity->get($field_name)->view($view_mode_id);
     } else {
         // Each part of a custom (non-Entity Display) view mode ID is separated
         // by a dash; the first part must be the module name.
         $mode_id_parts = explode('-', $view_mode_id, 2);
         $module = reset($mode_id_parts);
         $args = array($entity, $field_name, $view_mode_id, $langcode);
         $output = $this->moduleHandler()->invoke($module, 'quickedit_render_field', $args);
     }
     return $this->renderer->renderRoot($output);
 }
예제 #14
0
 /**
  * {@inheritdoc}
  *
  * The entire HTML: takes a #type 'page' and wraps it in a #type 'html'.
  */
 public function renderResponse(array $main_content, Request $request, RouteMatchInterface $route_match)
 {
     list($page, $title) = $this->prepare($main_content, $request, $route_match);
     if (!isset($page['#type']) || $page['#type'] !== 'page') {
         throw new \LogicException('Must be #type page');
     }
     $page['#title'] = $title;
     // Now render the rendered page.html.twig template inside the html.html.twig
     // template, and use the bubbled #attached metadata from $page to ensure we
     // load all attached assets.
     $html = ['#type' => 'html', 'page' => $page];
     // The special page regions will appear directly in html.html.twig, not in
     // page.html.twig, hence add them here, just before rendering html.html.twig.
     $this->buildPageTopAndBottom($html);
     // @todo https://www.drupal.org/node/2495001 Make renderRoot return a
     //       cacheable render array directly.
     $this->renderer->renderRoot($html);
     $content = $this->renderCache->getCacheableRenderArray($html);
     // Also associate the "rendered" cache tag. This allows us to invalidate the
     // entire render cache, regardless of the cache bin.
     $content['#cache']['tags'][] = 'rendered';
     $response = new HtmlResponse($content, 200, ['Content-Type' => 'text/html; charset=UTF-8']);
     return $response;
 }