diff --git a/includes/media.fields.inc b/includes/media.fields.inc index 267329cd2b4420752851c1d8bec6eab5c3c76275..e4f7a2eff837b03f2599763a67178bcc937ae2a6 100644 --- a/includes/media.fields.inc +++ b/includes/media.fields.inc @@ -557,10 +557,14 @@ function theme_media_widget_multiple($variables) { ); } + $table = array('header' => $headers, 'rows' => $rows, 'attributes' => array('id' => $table_id)); + + drupal_alter('media_widget_multiple', $table, $element); + drupal_add_tabledrag($table_id, 'order', 'sibling', $weight_class); $output = ''; - $output = empty($rows) ? '' : theme('table', array('header' => $headers, 'rows' => $rows, 'attributes' => array('id' => $table_id))); + $output = empty($rows) ? '' : theme('table', $table); $output .= drupal_render_children($element); return $output; } diff --git a/media.install b/media.install index c2d9888a583409e324dfd0749d0aa230f3aa552d..6aa7981dd6512827b3ab3d3522d1366952feaff9 100644 --- a/media.install +++ b/media.install @@ -87,8 +87,8 @@ function media_update_dependencies() { 'rules' => 7205, ); // Those updates require {file_type} table created. - $dependencies['media'][7204] = array( - 'file_entity' => 7201, + $dependencies['media'][7200] = array( + 'file_entity' => 7207, ); // Require {file_type}.mimetypes column before updating them. $dependencies['media'][7208] = array( diff --git a/media.module b/media.module index 7278203a6ba79bc901b1c60bcda714c9da5d3ae4..ba986a32c5600a86c45cd4d0bb7f06e1977604f3 100644 --- a/media.module +++ b/media.module @@ -1230,9 +1230,9 @@ function media_set_browser_params() { ); $params = array_intersect_key($params, array_flip($safe_options)); - // Retrieve the security sensitive options from the cache. + // If the cache is present, use its values instead of the GET parameters. if (!empty($params['options']) && is_string($params['options']) && $options = cache_get('media_options:' . $params['options'], 'cache_form')) { - $params = array_merge($options->data, $params); + $params = $options->data; } // Transform text 'true' and 'false' to actual booleans. diff --git a/media.views.inc b/media.views.inc index 70d5c2f1b80a181e57d3a3828858827744ca60d5..9640dde2c0b1bb2fab75169bea3cdfaf65929e94 100644 --- a/media.views.inc +++ b/media.views.inc @@ -33,6 +33,7 @@ function media_views_plugins() { 'help' => t('Display as a tab in the media browser.'), 'handler' => 'media_views_plugin_display_media_browser', 'theme' => 'views_view', + 'theme path' => drupal_get_path('module', 'views') . '/theme', 'base' => $base, 'use ajax' => TRUE, 'use pager' => TRUE, diff --git a/modules/media_wysiwyg/includes/media_wysiwyg.filter.inc b/modules/media_wysiwyg/includes/media_wysiwyg.filter.inc index 3be93ea19932132daff129d13bdbfd4df5d60e10..1cd6a50ed64cda47af30ed6b7d2a10e7e8575b2c 100644 --- a/modules/media_wysiwyg/includes/media_wysiwyg.filter.inc +++ b/modules/media_wysiwyg/includes/media_wysiwyg.filter.inc @@ -5,7 +5,7 @@ * Functions related to the WYSIWYG editor and the media input filter. */ -define('MEDIA_WYSIWYG_TOKEN_REGEX', '/\[\[.*?\]\]/s'); +define('MEDIA_WYSIWYG_TOKEN_REGEX', '/\[\[.+?"type":"media".+?\]\]/s'); /** * Filter callback for media markup filter. @@ -27,21 +27,70 @@ function media_wysiwyg_filter($text, $filter = NULL, $format = NULL, $langcode = return $rendered_text; } +/** + * Filter callback to configure media_filter_paragraph_fix filter. + */ +function _media_filter_paragraph_fix_settings($form, &$form_state, $filter, $format, $defaults) { + $filter->settings += $defaults; + $settings['replace'] = array( + '#type' => 'checkbox', + '#title' => t('Replace paragraph tags with DIV.media-p tags'), + '#default_value' => $filter->settings['replace'], + '#description' => t('Default behaviour is to strip out parent P tags of media elements rather than replacing these.'), + ); + return $settings; +} + /** * Filter callback to remove paragraph tags surrounding embedded media. */ -function media_wysiwyg_filter_paragraph_fix($text) { +function media_wysiwyg_filter_paragraph_fix($text, $filter) { $html_dom = filter_dom_load($text); + // Store Nodes to remove to avoid inferferring with the NodeList iteration. + $dom_nodes_to_remove = array(); foreach ($html_dom->getElementsByTagName('p') as $paragraph) { if (preg_match(MEDIA_WYSIWYG_TOKEN_REGEX, $paragraph->nodeValue)) { - $sibling = $paragraph->firstChild; - do { - $next = $sibling->nextSibling; - $paragraph->parentNode->insertBefore($sibling, $paragraph); - } while ($sibling = $next); - $paragraph->parentNode->removeChild($paragraph); + if (empty($filter->settings['replace'])) { + $sibling = $paragraph->firstChild; + do { + $next = $sibling->nextSibling; + $paragraph->parentNode->insertBefore($sibling, $paragraph); + } while ($sibling = $next); + $dom_nodes_to_remove[] = $paragraph; + } + else { + // Clone the P node into a DIV node. + $div = $html_dom->createElement('div'); + $sibling = $paragraph->firstChild; + do { + $next = $sibling->nextSibling; + $div->appendChild($sibling); + } while ($sibling = $next); + + $classes = array('media-p'); + if ($paragraph->hasAttributes()) { + foreach ($paragraph->attributes as $attr) { + $name = $attr->nodeName; + $value = $attr->nodeValue; + if (strtolower($name) == 'class') { + $classes[] = $value; + } + else { + // Supressing errors with ID attribute or duplicate properties. + @$div->setAttribute($name, $value); + } + } + } + $div->setAttribute('class', implode(' ', $classes)); + + $paragraph->parentNode->insertBefore($div, $paragraph); + $dom_nodes_to_remove[] = $paragraph; + } } } + foreach ($dom_nodes_to_remove as $paragraph) { + $paragraph->parentNode->removeChild($paragraph); + } $text = filter_dom_serialize($html_dom); return $text; } diff --git a/modules/media_wysiwyg/js/media_wysiwyg.filter.js b/modules/media_wysiwyg/js/media_wysiwyg.filter.js index 0f267d463b58b73a5f587351bc28ea2a9b5c2e94..ca8ba7a2eb9b2eca44c092f09a4f14de9288a089 100644 --- a/modules/media_wysiwyg/js/media_wysiwyg.filter.js +++ b/modules/media_wysiwyg/js/media_wysiwyg.filter.js @@ -175,7 +175,8 @@ Drupal.media.filter.ensure_tagmap(); // Locate and process all the media placeholders in the WYSIWYG content. - var contentElements = $('
').html(content); // TODO: once baseline jQuery is 1.8+, switch to using $.parseHTML(content) + var contentElements = $('
'); // TODO: once baseline jQuery is 1.8+, switch to using $.parseHTML(content) + contentElements.get(0).innerHTML = content; var mediaElements = contentElements.find('.media-element'); if (mediaElements) { $(mediaElements).each(function (i) { diff --git a/modules/media_wysiwyg/media_wysiwyg.info b/modules/media_wysiwyg/media_wysiwyg.info index 93b8a3aa999603137d633e913676c049e03ee69c..492b815c935719e482d85443c237a4a2cad1fa2e 100644 --- a/modules/media_wysiwyg/media_wysiwyg.info +++ b/modules/media_wysiwyg/media_wysiwyg.info @@ -12,5 +12,6 @@ test_dependencies[] = wysiwyg files[] = media_wysiwyg.test files[] = tests/media_wysiwyg.file_usage.test files[] = tests/media_wysiwyg.macro.test +files[] = tests/media_wysiwyg.paragraph_fix_filter.test configure = admin/config/media/browser diff --git a/modules/media_wysiwyg/media_wysiwyg.module b/modules/media_wysiwyg/media_wysiwyg.module index 6c122f3c8c361f3e3168caa32aa61fa5b9eb6c9c..483e2d0f214386f03a2c2b41363e4f2aa537f0a0 100644 --- a/modules/media_wysiwyg/media_wysiwyg.module +++ b/modules/media_wysiwyg/media_wysiwyg.module @@ -342,8 +342,12 @@ function media_wysiwyg_filter_info() { $filters['media_filter_paragraph_fix'] = array( 'title' => t('Ensure that embedded Media tags are not contained in paragraphs'), - 'description' => t('This filter will strip any paragraph tags surrounding embedded Media tags. This helps to avoid the chopped up markup that can result from unexpectedly closed paragraph tags. This filter should be positioned above (before) the "Convert Media tags to markup" filter.'), + 'description' => t('This filter will fix any paragraph tags surrounding embedded Media tags. This helps to avoid the chopped up markup that can result from unexpectedly closed paragraph tags. This filter should be positioned above (before) the "Convert Media tags to markup" filter.'), 'process callback' => 'media_wysiwyg_filter_paragraph_fix', + 'settings callback' => '_media_filter_paragraph_fix_settings', + 'default settings' => array( + 'replace' => 0, + ), 'weight' => 1, ); diff --git a/modules/media_wysiwyg/media_wysiwyg.test b/modules/media_wysiwyg/media_wysiwyg.test index 6b0aaa3777049da314425daa28fc762151f071ea..117aab57b8742d055ea4e9154553c62c97ae5ce7 100644 --- a/modules/media_wysiwyg/media_wysiwyg.test +++ b/modules/media_wysiwyg/media_wysiwyg.test @@ -58,9 +58,11 @@ abstract class MediaWYSIWYGTestHelper extends DrupalWebTestCase { ); // Create the file usage markup. + $markup .= '

Intro paragraph

'; for ($i = 1; $i <= $count; $i++) { $markup .= '

[[' . drupal_json_encode($data) . ']]

'; } + $markup .= '

Finish paragraph

'; return $markup; } diff --git a/modules/media_wysiwyg/tests/media_wysiwyg.paragraph_fix_filter.test b/modules/media_wysiwyg/tests/media_wysiwyg.paragraph_fix_filter.test new file mode 100644 index 0000000000000000000000000000000000000000..5c6f6c59061e2c96e4225cf3d61995ae2326a57b --- /dev/null +++ b/modules/media_wysiwyg/tests/media_wysiwyg.paragraph_fix_filter.test @@ -0,0 +1,165 @@ +]*media\-element\-container[^>]*>/i'; + + /** + * Defines the regex to test for in the raw body field source. + * + * @var string + */ + protected $regexpPWrapped = '/]*>
]*media\-element\-container[^>]*>/i'; + + /** + * Defines the regex to test for the P replacement filter. + * + * @var string + */ + protected $regexpReplaced = '/
t('Media WYSIWYG Paragraph Filter Test'), + 'description' => t('Tests that this media filter is working.'), + 'group' => t('Media WYSIWYG'), + 'dependencies' => array('token'), + ); + } + + /** + * Set-up the system for testing without the filter enabled. + */ + public function setUp() { + parent::setUp('token'); + + // Create and log in a user. + $account = $this->drupalCreateUser(array( + 'create article content', + 'administer filters', + 'use text format filtered_html', + )); + $this->drupalLogin($account); + + // Enable the media filter for full html. + $edit = array( + 'filters[media_filter][status]' => TRUE, + 'filters[filter_autop][status]' => FALSE, + 'filters[filter_html][status]' => FALSE, + 'filters[filter_htmlcorrector][status]' => FALSE, + ); + $this->drupalPost('admin/config/content/formats/filtered_html', $edit, t('Save configuration')); + } + + /** + * Test image media overrides. + */ + public function testMediaFilterParagraphFixMultipleImages() { + $files = $this->drupalGetTestFiles('image'); + $file = file_save($files[0]); + + // Create a node to test with 3 images. + $nid = $this->createNode($file->fid); + $node = node_load($nid); + $node->body[LANGUAGE_NONE][0]['value'] = $this->generateJsonTokenMarkup($file->fid, 3); + node_save($node); + + // Check without the filter enabled. + $html = $this->drupalGet('node/' . $nid); + $count = preg_match_all($this->regexpMediaTag, $html); + $this->assertEqual($count, 3, t('Three media tags found, found @count.', array('@count' => $count))); + + $count = preg_match_all($this->regexpPWrapped, $html); + $this->assertEqual($count, 3, t('Three media tags with original wrapping HTML present, found @count.', array('@count' => $count))); + + $count = preg_match_all($this->regexpReplaced, $html); + $this->assertEqual($count, 0, t('No media tags with P replaced present, found @count.', array('@count' => $count))); + + // Enable the default P fix filter. + $edit = array( + 'filters[media_filter_paragraph_fix][status]' => TRUE, + ); + $this->drupalPost('admin/config/content/formats/filtered_html', $edit, t('Save configuration')); + $html = $this->drupalGet('node/' . $nid); + + $count = preg_match_all($this->regexpMediaTag, $html); + $this->assertEqual($count, 3, t('Three media tags found, found @count.', array('@count' => $count))); + + $count = preg_match_all($this->regexpPWrapped, $html); + $this->assertEqual($count, 0, t('No media tags with original wrapping HTML present, found @count.', array('@count' => $count))); + + $count = preg_match_all($this->regexpReplaced, $html); + $this->assertEqual($count, 0, t('No media tags with P replaced present, found @count.', array('@count' => $count))); + + // Enable the replace P fix filter option. + $edit = array( + 'filters[media_filter_paragraph_fix][settings][replace]' => TRUE, + ); + $this->drupalPost('admin/config/content/formats/filtered_html', $edit, t('Save configuration')); + $html = $this->drupalGet('node/' . $nid); + + $count = preg_match_all($this->regexpMediaTag, $html); + $this->assertEqual($count, 3, t('Three media tags found, found @count.', array('@count' => $count))); + + $count = preg_match_all($this->regexpPWrapped, $html); + $this->assertEqual($count, 0, t('No media tags with original wrapping HTML present, found @count.', array('@count' => $count))); + + $count = preg_match_all($this->regexpReplaced, $html); + $this->assertEqual($count, 3, t('Three media tags with P replaced present, found @count.', array('@count' => $count))); + } + + /** + * Test image media overrides. + */ + public function testMediaFilterParagraphFixDefault() { + $files = $this->drupalGetTestFiles('image'); + $file = file_save($files[0]); + + // Create a node to test with. + $nid = $this->createNode($file->fid); + + // Check without the filter enabled. + $this->drupalGet('node/' . $nid); + $this->assertPattern($this->regexpPWrapped, t('Nested media DIV tags within paragraphs without filter.')); + $this->assertNoPattern($this->regexpReplaced, t('No replacement DIV tag found without filter.')); + + // Enable the default P fix filter. + $edit = array( + 'filters[media_filter_paragraph_fix][status]' => TRUE, + ); + $this->drupalPost('admin/config/content/formats/filtered_html', $edit, t('Save configuration')); + + // Retest the content to check nested paragraphs are removed. + $this->drupalGet('node/' . $nid); + $this->assertNoPattern($this->regexpPWrapped, t('Nested media DIV tags within paragraphs with filter defaults.')); + $this->assertNoPattern($this->regexpReplaced, t('No replacement DIV tag found with filter defaults.')); + + // Enable replacement option. + $edit = array( + 'filters[media_filter_paragraph_fix][settings][replace]' => TRUE, + ); + $this->drupalPost('admin/config/content/formats/filtered_html', $edit, t('Save configuration')); + + // Test that the replace text was found. + $this->drupalGet('node/' . $nid); + $this->assertNoPattern($this->regexpPWrapped, t('No nested media DIV tags within paragraphs with filter P replacement.')); + $this->assertPattern($this->regexpReplaced, t('No replacement DIV tag found with filter P replacement.')); + } + +}