/**
  * Additional #pre_render callback for 'text_format' elements.
  */
 function preRenderTextFormat(array $element)
 {
     // Allow modules to programmatically enforce no client-side editor by
     // setting the #editor property to FALSE.
     if (isset($element['#editor']) && !$element['#editor']) {
         return $element;
     }
     // filter_process_format() copies properties to the expanded 'value' child
     // element, including the #pre_render property. Skip this text format
     // widget, if it contains no 'format'.
     if (!isset($element['format'])) {
         return $element;
     }
     $format_ids = array_keys($element['format']['format']['#options']);
     // Early-return if no text editor is associated with any of the text formats.
     $editors = Editor::loadMultiple($format_ids);
     if (count($editors) === 0) {
         return $element;
     }
     // Use a hidden element for a single text format.
     $field_id = $element['value']['#id'];
     if (!$element['format']['format']['#access']) {
         // Use the first (and only) available text format.
         $format_id = $format_ids[0];
         $element['format']['editor'] = array('#type' => 'hidden', '#name' => $element['format']['format']['#name'], '#value' => $format_id, '#attributes' => array('class' => array('editor'), 'data-editor-for' => $field_id));
     } else {
         $element['format']['format']['#attributes']['class'][] = 'editor';
         $element['format']['format']['#attributes']['data-editor-for'] = $field_id;
     }
     // Hide the text format's filters' guidelines of those text formats that have
     // a text editor associated: they're rather useless when using a text editor.
     foreach ($editors as $format_id => $editor) {
         $element['format']['guidelines'][$format_id]['#access'] = FALSE;
     }
     // Attach Text Editor module's (this module) library.
     $element['#attached']['library'][] = 'editor/drupal.editor';
     // Attach attachments for all available editors.
     $element['#attached'] = drupal_merge_attached($element['#attached'], $this->pluginManager->getAttachments($format_ids));
     // Apply XSS filters when editing content if necessary. Some types of text
     // editors cannot guarantee that the end user won't become a victim of XSS.
     if (!empty($element['value']['#value'])) {
         $original = $element['value']['#value'];
         $format = FilterFormat::load($element['format']['format']['#value']);
         // Ensure XSS-safety for the current text format/editor.
         $filtered = editor_filter_xss($original, $format);
         if ($filtered !== FALSE) {
             $element['value']['#value'] = $filtered;
         }
         // Only when the user has access to multiple text formats, we must add data-
         // attributes for the original value and change tracking, because they are
         // only necessary when the end user can switch between text formats/editors.
         if ($element['format']['format']['#access']) {
             $element['value']['#attributes']['data-editor-value-is-changed'] = 'false';
             $element['value']['#attributes']['data-editor-value-original'] = $original;
         }
     }
     return $element;
 }
 /**
  * #post_render_cache callback; replaces placeholder with comment form.
  *
  * @param array $element
  *   The renderable array that contains the to be replaced placeholder.
  * @param array $context
  *   An array with the following keys:
  *   - entity_type: an entity type
  *   - entity_id: an entity ID
  *   - field_name: a comment field name
  *
  * @return array
  *   A renderable array containing the comment form.
  */
 public function renderForm(array $element, array $context)
 {
     $field_name = $context['field_name'];
     $entity = $this->entityManager->getStorage($context['entity_type'])->load($context['entity_id']);
     $field_storage = FieldStorageConfig::loadByName($entity->getEntityTypeId(), $field_name);
     $values = array('entity_type' => $entity->getEntityTypeId(), 'entity_id' => $entity->id(), 'field_name' => $field_name, 'comment_type' => $field_storage->getSetting('bundle'), 'pid' => NULL);
     $comment = $this->entityManager->getStorage('comment')->create($values);
     $form = $this->entityFormBuilder->getForm($comment);
     $markup = drupal_render($form);
     $callback = 'comment.post_render_cache:renderForm';
     $placeholder = drupal_render_cache_generate_placeholder($callback, $context);
     $element['#markup'] = str_replace($placeholder, $markup, $element['#markup']);
     $element['#attached'] = drupal_merge_attached($element['#attached'], $form['#attached']);
     return $element;
 }
 /**
  * Adds cache tags associated with the processed text.
  *
  * @param array $cache_tags
  *   The cache tags to be added.
  *
  * @return $this
  */
 public function addCacheTags(array $cache_tags)
 {
     $this->cacheTags = drupal_merge_attached($this->cacheTags, $cache_tags);
     return $this;
 }
 /**
  * Tests justs JavaScript and JavaScript setting asset merging.
  */
 function testJsSettingMerging()
 {
     $a['#attached'] = array('js' => array('foo.js' => array(), 'bar.js' => array()), 'drupalSettings' => ['foo' => ['d']]);
     $b['#attached'] = array('js' => array('baz.js' => array()), 'drupalSettings' => ['bar' => ['a', 'b', 'c']]);
     $expected['#attached'] = array('js' => array('foo.js' => array(), 'bar.js' => array(), 'baz.js' => array()), 'drupalSettings' => ['foo' => ['d'], 'bar' => ['a', 'b', 'c']]);
     $this->assertIdentical($expected['#attached'], drupal_merge_attached($a['#attached'], $b['#attached']), 'Attachments merged correctly.');
     // Merging in the opposite direction yields the opposite JS setting asset
     // order.
     $expected['#attached'] = array('js' => array('baz.js' => array(), 'foo.js' => array(), 'bar.js' => array()), 'drupalSettings' => ['bar' => ['a', 'b', 'c'], 'foo' => ['d']]);
     $this->assertIdentical($expected['#attached'], drupal_merge_attached($b['#attached'], $a['#attached']), 'Attachments merged correctly; opposite merging yields opposite order.');
     // Merging with duplicates (simple case).
     $b['#attached']['drupalSettings']['foo'] = ['a', 'b', 'c'];
     $expected['#attached'] = array('js' => array('foo.js' => array(), 'bar.js' => array(), 'baz.js' => array()), 'drupalSettings' => ['foo' => ['a', 'b', 'c'], 'bar' => ['a', 'b', 'c']]);
     $this->assertIdentical($expected['#attached'], drupal_merge_attached($a['#attached'], $b['#attached']));
     // Merging with duplicates (simple case) in the opposite direction yields
     // the opposite JS setting asset order, but also opposite overriding order.
     $expected['#attached'] = array('js' => array('baz.js' => array(), 'foo.js' => array(), 'bar.js' => array()), 'drupalSettings' => ['bar' => ['a', 'b', 'c'], 'foo' => ['d', 'b', 'c']]);
     $this->assertIdentical($expected['#attached'], drupal_merge_attached($b['#attached'], $a['#attached']));
     // Merging with duplicates: complex case.
     // Only the second of these two entries should appear in drupalSettings.
     $build = array();
     $build['a']['#attached']['drupalSettings']['commonTest'] = 'firstValue';
     $build['b']['#attached']['drupalSettings']['commonTest'] = 'secondValue';
     // Only the second of these entries should appear in drupalSettings.
     $build['a']['#attached']['drupalSettings']['commonTestJsArrayLiteral'] = ['firstValue'];
     $build['b']['#attached']['drupalSettings']['commonTestJsArrayLiteral'] = ['secondValue'];
     // Only the second of these two entries should appear in drupalSettings.
     $build['a']['#attached']['drupalSettings']['commonTestJsObjectLiteral'] = ['key' => 'firstValue'];
     $build['b']['#attached']['drupalSettings']['commonTestJsObjectLiteral'] = ['key' => 'secondValue'];
     // Real world test case: multiple elements in a render array are adding the
     // same (or nearly the same) JavaScript settings. When merged, they should
     // contain all settings and not duplicate some settings.
     $settings_one = array('moduleName' => array('ui' => array('button A', 'button B'), 'magical flag' => 3.14159265359));
     $build['a']['#attached']['drupalSettings']['commonTestRealWorldIdentical'] = $settings_one;
     $build['b']['#attached']['drupalSettings']['commonTestRealWorldIdentical'] = $settings_one;
     $settings_two_a = array('moduleName' => array('ui' => array('button A', 'button B', 'button C'), 'magical flag' => 3.14159265359, 'thingiesOnPage' => array('id1' => array())));
     $build['a']['#attached']['drupalSettings']['commonTestRealWorldAlmostIdentical'] = $settings_two_a;
     $settings_two_b = array('moduleName' => array('ui' => array('button D', 'button E'), 'magical flag' => 3.14, 'thingiesOnPage' => array('id2' => array())));
     $build['b']['#attached']['drupalSettings']['commonTestRealWorldAlmostIdentical'] = $settings_two_b;
     $merged = drupal_merge_attached($build['a']['#attached'], $build['b']['#attached']);
     // Test whether #attached can be used to override a previous setting.
     $this->assertIdentical('secondValue', $merged['drupalSettings']['commonTest']);
     // Test whether #attached can be used to add and override a JavaScript
     // array literal (an indexed PHP array) values.
     $this->assertIdentical('secondValue', $merged['drupalSettings']['commonTestJsArrayLiteral'][0]);
     // Test whether #attached can be used to add and override a JavaScript
     // object literal (an associate PHP array) values.
     $this->assertIdentical('secondValue', $merged['drupalSettings']['commonTestJsObjectLiteral']['key']);
     // Test whether the two real world cases are handled correctly: the first
     // adds the exact same settings twice and hence tests idempotency, the
     // second adds *almost* the same settings twice: the second time, some
     // values are altered, and some key-value pairs are added.
     $settings_two['moduleName']['thingiesOnPage']['id1'] = array();
     $this->assertIdentical($settings_one, $merged['drupalSettings']['commonTestRealWorldIdentical']);
     $expected_settings_two = $settings_two_a;
     $expected_settings_two['moduleName']['ui'][0] = 'button D';
     $expected_settings_two['moduleName']['ui'][1] = 'button E';
     $expected_settings_two['moduleName']['ui'][2] = 'button C';
     $expected_settings_two['moduleName']['magical flag'] = 3.14;
     $expected_settings_two['moduleName']['thingiesOnPage']['id2'] = [];
     $this->assertIdentical($expected_settings_two, $merged['drupalSettings']['commonTestRealWorldAlmostIdentical']);
 }
 /**
  * Tests justs JavaScript and JavaScript setting asset merging.
  */
 function testJsSettingMerging()
 {
     $a['#attached'] = array('js' => array('foo.js' => array(), array('type' => 'setting', 'data' => array('foo' => array('d'))), 'bar.js' => array()));
     $b['#attached'] = array('js' => array(83 => array('type' => 'setting', 'data' => array('bar' => array('a', 'b', 'c'))), 'baz.js' => array()));
     $expected['#attached'] = array('js' => array('foo.js' => array(), 0 => array('type' => 'setting', 'data' => array('foo' => array('d'))), 'bar.js' => array(), 1 => array('type' => 'setting', 'data' => array('bar' => array('a', 'b', 'c'))), 'baz.js' => array()));
     $this->assertIdentical($expected['#attached'], drupal_merge_attached($a['#attached'], $b['#attached']), 'Attachments merged correctly.');
     // Merging in the opposite direction yields the opposite JS setting asset
     // order.
     $expected['#attached'] = array('js' => array(0 => array('type' => 'setting', 'data' => array('bar' => array('a', 'b', 'c'))), 'baz.js' => array(), 'foo.js' => array(), 1 => array('type' => 'setting', 'data' => array('foo' => array('d'))), 'bar.js' => array()));
     $this->assertIdentical($expected['#attached'], drupal_merge_attached($b['#attached'], $a['#attached']), 'Attachments merged correctly; opposite merging yields opposite order.');
     // Merging with duplicates: JavaScript setting duplicates are simply
     // retained, it's up to the rest of the system (drupal_merge_js_settings())
     // to handle duplicates.
     $b['#attached']['js'][] = array('type' => 'setting', 'data' => array('foo' => array('a', 'b', 'c')));
     $expected['#attached'] = array('js' => array('foo.js' => array(), 0 => array('type' => 'setting', 'data' => array('foo' => array('d'))), 'bar.js' => array(), 1 => array('type' => 'setting', 'data' => array('bar' => array('a', 'b', 'c'))), 'baz.js' => array(), 2 => array('type' => 'setting', 'data' => array('foo' => array('a', 'b', 'c')))));
     $this->assertIdentical($expected['#attached'], drupal_merge_attached($a['#attached'], $b['#attached']), 'Attachments merged correctly; JavaScript asset duplicates removed, JavaScript setting asset duplicates retained.');
 }