/** * {@inheritdoc} */ public function process($text, $langcode) { $this->currentFilterProcessResult = new FilterProcessResult($text); $this->currentFilterProcessResult->setProcessedText(preg_replace_callback('/\\[currency-localize:([a-z]{3}):(.+?)\\]/i', [$this, 'processCallback'], $text)); $result = $this->currentFilterProcessResult; unset($this->currentFilterProcessResult); return $result; }
/** * {@inheritdoc} */ public function process($text, $langcode) { $result = new FilterProcessResult($text); // Track if widget has been found so that we can attached the // jquery_ui_filter library and settings. $has_widget = FALSE; foreach (self::$widgets as $name => $widget) { if (strpos($text, '[' . $name) === FALSE) { continue; } $has_widget = TRUE; // Remove block tags around tokens. $text = preg_replace('#<(p|div)[^>]*>\\s*(\\[/?' . $name . '[^]]*\\])\\s*</\\1>#', '\\2', $text); // Convert opening [token] to opening <div data-ui-*> tag. $text = preg_replace_callback('#\\[' . $name . '([^]]*)?\\]#is', function ($match) use($name) { // Set data-ui-* attributes from role and options. $attributes = new Attribute(['data-ui-role' => $name]); $options = $this->parseOptions($match[1]); foreach ($options as $name => $value) { $attributes->setAttribute('data-ui-' . $name, $value); } return "<div{$attributes}>"; }, $text); // Convert closing [/token] to closing </div> tag. $text = str_replace('[/' . $name . ']', '</div>', $text); } if ($has_widget) { $result->setAttachments(['library' => ['jquery_ui_filter/jquery_ui_filter'], 'drupalSettings' => ['jquery_ui_filter' => \Drupal::config('jquery_ui_filter.settings')->get()]]); } return $result->setProcessedText($text); }
/** * {@inheritdoc} */ public function process($text, $langcode) { $result = new FilterProcessResult($text); $placeholder = $result->createPlaceholder('\\Drupal\\filter_test\\Plugin\\Filter\\FilterTestPlaceholders::renderDynamicThing', ['llama']); $result->setProcessedText($text . '<p>' . $placeholder . '</p>'); return $result; }
/** * {@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; }
/** * {@inheritdoc} */ public function process($text, $langcode) { $result = new FilterProcessResult($text); if (stristr($text, 'data-entity-type="file"') !== FALSE) { $dom = Html::load($text); $xpath = new \DOMXPath($dom); $processed_uuids = array(); foreach ($xpath->query('//*[@data-entity-type="file" and @data-entity-uuid]') as $node) { $uuid = $node->getAttribute('data-entity-uuid'); // If there is a 'src' attribute, set it to the file entity's current // URL. This ensures the URL works even after the file location changes. if ($node->hasAttribute('src')) { $file = $this->entityManager->loadEntityByUuid('file', $uuid); if ($file) { $node->setAttribute('src', file_url_transform_relative(file_create_url($file->getFileUri()))); } } // Only process the first occurrence of each file UUID. if (!isset($processed_uuids[$uuid])) { $processed_uuids[$uuid] = TRUE; $file = $this->entityManager->loadEntityByUuid('file', $uuid); if ($file) { $result->addCacheTags($file->getCacheTags()); } } } $result->setProcessedText(Html::serialize($dom)); } return $result; }
/** * {@inheritdoc} */ public function process($text, $langcode) { $result = new FilterProcessResult($text); if (strpos($text, '<oembed') !== FALSE) { $result->setProcessedText($this->ckeditor_media_embed->processEmbeds($text)); } return $result; }
/** * {@inheritdoc} */ public function process($text, $langcode) { $result = new FilterProcessResult($text); // Replace node macros with entity content. $pattern = '/\\[mailchimp_campaign\\|entity_type=(\\w+)\\|entity_id=(\\d+)\\|view_mode=(\\w+)\\]/s'; $text = preg_replace_callback($pattern, array($this, 'mailchimp_campaign_process_callback'), $text); // Convert URL to absolute. $text = $this->convertUrl($text); $result->setProcessedText($text); return $result; }
/** * {@inheritdoc} */ public function process($text, $langcode) { $new_text = $text; $filter_result = new FilterProcessResult($text); if (preg_match('/\\[survey\\:.+\\]/', $text, $result)) { $token = $result[0]; $start = strpos($token, ':') + 1; $length = strpos($token, ']') - $start; $id = substr($token, $start, $length); $block = Block::load($id); if ($block) { $replace = $block->get('settings')['html']; $new_text = str_replace($token, $replace, $text); $filter_result->setProcessedText($new_text); $filter_result->setCacheTags($block->getCacheTags()); } } return $filter_result; }
/** * {@inheritdoc} */ public function process($text, $langcode) { $result = new FilterProcessResult($text); if (stristr($text, 'data-caption') !== FALSE) { $dom = Html::load($text); $xpath = new \DOMXPath($dom); foreach ($xpath->query('//*[@data-caption]') as $node) { // Read the data-caption attribute's value, then delete it. $caption = Html::escape($node->getAttribute('data-caption')); $node->removeAttribute('data-caption'); // Sanitize caption: decode HTML encoding, limit allowed HTML tags; only // allow inline tags that are allowed by default, plus <br>. $caption = Html::decodeEntities($caption); $caption = FilteredMarkup::create(Xss::filter($caption, array('a', 'em', 'strong', 'cite', 'code', 'br'))); // The caption must be non-empty. if (Unicode::strlen($caption) === 0) { continue; } // Given the updated node and caption: re-render it with a caption, but // bubble up the value of the class attribute of the captioned element, // this allows it to collaborate with e.g. the filter_align filter. $tag = $node->tagName; $classes = $node->getAttribute('class'); $node->removeAttribute('class'); $node = $node->parentNode->tagName === 'a' ? $node->parentNode : $node; $filter_caption = array('#theme' => 'filter_caption', '#node' => FilteredMarkup::create($node->C14N()), '#tag' => $tag, '#caption' => $caption, '#classes' => $classes); $altered_html = drupal_render($filter_caption); // Load the altered HTML into a new DOMDocument and retrieve the element. $updated_nodes = Html::load($altered_html)->getElementsByTagName('body')->item(0)->childNodes; foreach ($updated_nodes as $updated_node) { // Import the updated node from the new DOMDocument into the original // one, importing also the child nodes of the updated node. $updated_node = $dom->importNode($updated_node, TRUE); $node->parentNode->insertBefore($updated_node, $node); } // Finally, remove the original data-caption node. $node->parentNode->removeChild($node); } $result->setProcessedText(Html::serialize($dom))->addAttachments(array('library' => array('filter/caption'))); } return $result; }
/** * {@inheritdoc} */ public function process($text, $langcode) { $result = new FilterProcessResult($text); if (stristr($text, 'data-align') !== FALSE) { $dom = Html::load($text); $xpath = new \DOMXPath($dom); foreach ($xpath->query('//*[@data-align]') as $node) { // Read the data-align attribute's value, then delete it. $align = $node->getAttribute('data-align'); $node->removeAttribute('data-align'); // If one of the allowed alignments, add the corresponding class. if (in_array($align, array('left', 'center', 'right'))) { $classes = $node->getAttribute('class'); $classes = strlen($classes) > 0 ? explode(' ', $classes) : array(); $classes[] = 'align-' . $align; $node->setAttribute('class', implode(' ', $classes)); } } $result->setProcessedText(Html::serialize($dom)); } return $result; }
/** * {@inheritdoc} */ public function process($text, $langcode) { $result = new FilterProcessResult($text); if (stristr($text, '<img ') !== FALSE) { $dom = Html::load($text); $images = $dom->getElementsByTagName('img'); foreach ($images as $image) { $src = $image->getAttribute("src"); // The src must be non-empty. if (Unicode::strlen($src) === 0) { continue; } // The src must not already be an external URL if (stristr($src, 'http://') !== FALSE || stristr($src, 'https://') !== FALSE) { continue; } $url = Url::fromUri('internal:' . $src, array('absolute' => TRUE)); $url_string = $url->toString(); $image->setAttribute('src', $url_string); } $result->setProcessedText(Html::serialize($dom)); } return $result; }
/** * {@inheritdoc} */ public function process($text, $langcode) { $result = new FilterProcessResult($text); $dom = Html::load($text); $xpath = new \DOMXPath($dom); /** @var \DOMNode $node */ foreach ($xpath->query('//img') as $node) { // Read the data-align attribute's value, then delete it. $width = $node->getAttribute('width'); $height = $node->getAttribute('height'); $src = $node->getAttribute('src'); if (!UrlHelper::isExternal($src)) { if ($width || $height) { /** @var \DOMNode $element */ $element = $dom->createElement('a'); $element->setAttribute('href', $src); $node->parentNode->replaceChild($element, $node); $element->appendChild($node); } } } $result->setProcessedText(Html::serialize($dom)); return $result; }
/** * {@inheritdoc} */ public function process($text, $langcode) { $result = new FilterProcessResult($text); if (stristr($text, 'data-caption') !== FALSE || stristr($text, 'data-align') !== FALSE) { $caption_found = FALSE; $dom = Html::load($text); $xpath = new \DOMXPath($dom); foreach ($xpath->query('//*[@data-caption or @data-align]') as $node) { $caption = NULL; $align = NULL; // Retrieve, then remove the data-caption and data-align attributes. if ($node->hasAttribute('data-caption')) { $caption = String::checkPlain($node->getAttribute('data-caption')); $node->removeAttribute('data-caption'); // Sanitize caption: decode HTML encoding, limit allowed HTML tags; // only allow inline tags that are allowed by default, plus <br>. $caption = String::decodeEntities($caption); $caption = Xss::filter($caption, array('a', 'em', 'strong', 'cite', 'code', 'br')); // The caption must be non-empty. if (Unicode::strlen($caption) === 0) { $caption = NULL; } } if ($node->hasAttribute('data-align')) { $align = $node->getAttribute('data-align'); $node->removeAttribute('data-align'); // Only allow 3 values: 'left', 'center' and 'right'. if (!in_array($align, array('left', 'center', 'right'))) { $align = NULL; } } // Don't transform the HTML if there isn't a caption after validation. if ($caption === NULL) { // If there is a valid alignment, then transform the data-align // attribute to a corresponding alignment class. if ($align !== NULL) { $classes = $node->getAttribute('class'); $classes = strlen($classes) > 0 ? explode(' ', $classes) : array(); $classes[] = 'align-' . $align; $node->setAttribute('class', implode(' ', $classes)); } continue; } else { $caption_found = TRUE; } // Given the updated node, caption and alignment: re-render it with a // caption. $filter_caption = array('#theme' => 'filter_caption', '#node' => SafeMarkup::set($node->C14N()), '#tag' => $node->tagName, '#caption' => $caption, '#align' => $align); $altered_html = drupal_render($filter_caption); // Load the altered HTML into a new DOMDocument and retrieve the element. $updated_node = Html::load($altered_html)->getElementsByTagName('body')->item(0)->childNodes->item(0); // Import the updated node from the new DOMDocument into the original // one, importing also the child nodes of the updated node. $updated_node = $dom->importNode($updated_node, TRUE); // Finally, replace the original image node with the new image node! $node->parentNode->replaceChild($updated_node, $node); } $result->setProcessedText(Html::serialize($dom)); if ($caption_found) { $result->addAssets(array('library' => array('filter/caption'))); } } return $result; }