Commit 1faca421 authored by Paris Liakos's avatar Paris Liakos

Issue #2067063 by kaidjohnson, ParisLiakos Wysiwyg integration is broken

parent 5faa4bb4
......@@ -313,12 +313,11 @@ function media_token_to_markup($match, $wysiwyg = FALSE) {
$fields = media_filter_field_parser($tag_info);
$attributes = is_array($tag_info['attributes']) ? $tag_info['attributes'] : array();
$attribute_whitelist = variable_get('media__wysiwyg_allowed_attributes', array('height', 'width', 'hspace', 'vspace', 'border', 'align', 'style', 'class', 'id', 'usemap', 'data-picture-group', 'data-picture-align'));
$attribute_whitelist = variable_get('media__wysiwyg_allowed_attributes', _media_wysiwyg_allowed_attributes_default());
$settings['attributes'] = array_intersect_key($attributes, array_flip($attribute_whitelist));
$settings['fields'] = $fields;
if (!empty($tag_info['attributes']) && is_array($tag_info['attributes'])) {
$attribute_whitelist = variable_get('media__wysiwyg_allowed_attributes', array('height', 'width', 'hspace', 'vspace', 'border', 'align', 'style', 'class', 'id', 'usemap', 'data-picture-group', 'data-picture-align'));
$settings['attributes'] = array_intersect_key($tag_info['attributes'], array_flip($attribute_whitelist));
$settings['fields'] = $fields;
......@@ -668,18 +667,46 @@ function media_get_file_without_label($file, $view_mode, $settings = array()) {
// support simple formatters that don't do this, set the element attributes to
// what was requested, but not if the formatter applied its own logic for
// element attributes.
if (!isset($element['#attributes']) && isset($settings['attributes'])) {
$element['#attributes'] = $settings['attributes'];
if (isset($settings['attributes'])) {
if (empty($element['#attributes'])) {
$element['#attributes'] = $settings['attributes'];
}
// While this function may be called for any file type, images are a common
// use-case. theme_image() and theme_image_style() require the 'alt'
// attribute to be passed separately from the 'attributes' array (see
// http://drupal.org/node/999338). Until that's fixed, implement this
// special-case logic. Image formatters using other theme functions are
// responsible for their own 'alt' attribute handling. See
// theme_media_formatter_large_icon() for an example.
if (isset($settings['attributes']['alt']) && !isset($element['#alt']) && isset($element['#theme']) && in_array($element['#theme'], array('image', 'image_style'))) {
$element['#alt'] = $settings['attributes']['alt'];
// use-case, and image theme functions have their own structure for render
// arrays.
if (isset($element['#theme'])) {
switch ($element['#theme']) {
case 'image':
case 'image_style':
// theme_image() and theme_image_style() require the 'alt' attributes to
// be passed separately from the 'attributes' array. (see
// http://drupal.org/node/999338). Until that's fixed, implement this
// special-case logic. Image formatters using other theme functions are
// responsible for their own 'alt' attribute handling. See
// theme_media_formatter_large_icon() for an example.
if (empty($element['#alt']) && isset($settings['attributes']['alt'])) {
$element['#alt'] = $settings['attributes']['alt'];
}
break;
case 'image_formatter':
// theme_image_formatter() requires the attributes to be
// set on the item rather than the element itself.
if (empty($element['#item']['attributes'])) {
$element['#item']['attributes'] = $settings['attributes'];
}
// theme_image_formatter() also requires alt, title, height, and
// width attributes to be set on the item rather than within its
// attributes array.
foreach (array('alt', 'title', 'width', 'height') as $attr) {
if (isset($settings['attributes'][$attr])) {
$element['#item'][$attr] = $settings['attributes'][$attr];
}
}
break;
}
}
}
......
......@@ -14,14 +14,14 @@
* @param content
*/
replaceTokenWithPlaceholder: function(content) {
var tagmap = Drupal.media.filter.ensure_tagmap(),
Drupal.media.filter.ensure_tagmap()
var tagmap = Drupal.settings.tagmap,
matches = content.match(/\[\[.*?\]\]/g),
media_definition,
id = 0;
media_definition;
if (matches) {
var i = 1;
for (var macro in tagmap) {
// We cant use indexOf because of IE.
var index = $.inArray(macro, matches);
if (index !== -1) {
var media_json = macro.replace('[[', '').replace(']]', '');
......@@ -38,10 +38,9 @@
var element = Drupal.media.filter.create_element(tagmap[macro], media_definition);
var markup = Drupal.media.filter.outerHTML(element);
content = content.replace(macro, Drupal.media.filter.getWrapperStart(i) + markup + Drupal.media.filter.getWrapperEnd(i));
content = content.replace(macro, markup);
}
}
i++;
}
}
return content;
......@@ -52,29 +51,23 @@
* @param content
*/
replacePlaceholderWithToken: function(content) {
var tagmap = Drupal.media.filter.ensure_tagmap();
var i = 1;
for (var macro in tagmap) {
var startTag = Drupal.media.filter.getWrapperStart(i), endTag = Drupal.media.filter.getWrapperEnd(i);
var startPos = content.indexOf(startTag), endPos = content.indexOf(endTag);
if (startPos !== -1 && endPos !== -1) {
// If the placeholder wrappers are empty, remove the macro too.
if (endPos - startPos - startTag.length === 0) {
macro = '';
}
content = content.substr(0, startPos) + macro + content.substr(endPos + (new String(endTag)).length);
}
i++;
}
return content;
},
getWrapperStart: function(i) {
return '<!--MEDIA-WRAPPER-START-' + i + '-->';
},
Drupal.media.filter.ensure_tagmap();
// Convert all xhtml markup to html for reliable matching/replacing.
content = content.replace(/[\s]\/\>/g, '>');
// Re-build the macros in case any element has changed in the editor.
$('.media-element', content).each(function(i, element) {
var markup = Drupal.media.filter.outerHTML($(element));
macro = Drupal.media.filter.create_macro($(element));
// Store the macro => html for more efficient rendering in
// replaceTokenWithPlaceholder().
Drupal.settings.tagmap[macro] = markup;
// Replace the media element with its macro.
content = content.replace(markup, macro);
});
getWrapperEnd: function(i) {
return '<!--MEDIA-WRAPPER-END-' + i + '-->';
return content;
},
/**
......@@ -199,7 +192,7 @@
* @param element (jQuery object)
*/
outerHTML: function (element) {
return $('<div>').append(element.eq(0).clone()).html();
return element[0].outerHTML || $('<div>').append(element.eq(0).clone()).html();
},
/**
......@@ -225,9 +218,9 @@
}
Drupal.settings.tagmap[macro] = markup;
// Return the wrapped html code to insert in an editor and use it with
// Return the html code to insert in an editor and use it with
// replacePlaceholderWithToken()
return Drupal.media.filter.getWrapperStart(i) + markup + Drupal.media.filter.getWrapperEnd(i);
return markup;
},
/**
......
......@@ -20,5 +20,6 @@ files[] = includes/media_views_plugin_style_media_browser.inc
files[] = tests/media.test
files[] = tests/media.entity.test
files[] = tests/media.file.usage.test
files[] = tests/media.macro.test
configure = admin/config/media/browser
......@@ -1049,6 +1049,24 @@ function media_file_displays_alter(&$displays, $file, $view_mode) {
$file->{$field_name} = $value;}
}
}
// Alt and title are special.
// @see file_entity_file_load
$alt = variable_get('file_entity_alt', '[file:field_file_image_alt_text]');
$title = variable_get('file_entity_title', '[file:field_file_image_title_text]');
$replace_options = array(
'clear' => TRUE,
'sanitize' => FALSE,
);
// Load alt and title text from fields.
if (!empty($alt)) {
$file->alt = token_replace($alt, array('file' => $file), $replace_options);
}
if (!empty($title)) {
$file->title = token_replace($title, array('file' => $file), $replace_options);
}
}
/**
......@@ -1281,3 +1299,28 @@ function _media_get_migratable_file_types() {
return array_diff($types, $enabled_types);
}
/**
* Returns the default set of allowed attributes for use with WYSIWYG.
*
* @return array
* An array of whitelisted attributes.
*/
function _media_wysiwyg_allowed_attributes_default() {
return array(
'alt',
'title',
'height',
'width',
'hspace',
'vspace',
'border',
'align',
'style',
'class',
'id',
'usemap',
'data-picture-group',
'data-picture-align',
);
}
......@@ -22,79 +22,13 @@ class MediaFileUsageTest extends MediaTestHelper {
* Enable media and file entity modules for testing.
*/
public function setUp() {
parent::setUp(array('media', 'file_entity'));
parent::setUp();
// Create and log in a user.
$account = $this->drupalCreateUser(array('administer nodes', 'create article content'));
$this->drupalLogin($account);
}
/**
* Generates markup to be inserted for a file.
*
* This is a PHP version of InsertMedia.insert() from js/wysiwyg-media.js.
*
* @param int $fid
* Drupal file id
* @param int $count
* Quantity of markup to insert
*
* @return string
* Filter markup.
*/
private function generateFileMarkup($fid, $count = 1) {
$file_usage_markup = '';
// Build the data that is used in a media tag.
$data = array(
'fid' => $fid,
'type' => 'media',
'view_mode' => 'preview',
'attributes' => array(
'height' => 100,
'width' => 100,
'classes' => 'media-element file_preview',
)
);
// Create the file usage markup.
for ($i = 1; $i <= $count; $i++) {
$file_usage_markup .= '<p>[[' . drupal_json_encode($data) . ']]</p>';
}
return $file_usage_markup;
}
/**
* Utility function to create a test node.
*
* @param int $fid
* Create the node with media markup in the body field
*
* @return int
* Returns the node id
*/
private function createNode($fid = FALSE) {
$markup = '';
if (! empty($fid)) {
$markup = $this->generateFileMarkup($fid);
}
// Create an article node with file markup in the body field.
$edit = array(
'title' => $this->randomName(8),
'body[und][0][value]' => $markup,
);
// Save the article node. First argument is the URL, then the value array
// and the third is the label the button that should be "clicked".
$this->drupalPost('node/add/article', $edit, t('Save'));
// Get the article node that was saved by the unique title.
$node = $this->drupalGetNodeByTitle($edit['title']);
return $node->nid;
}
/**
* Tests the tracking of file usages for files submitted via the WYSIWYG editor.
*/
......@@ -133,7 +67,7 @@ class MediaFileUsageTest extends MediaTestHelper {
// Create a new revision that has two instances of the file. File usage will
// be 4.
$node = node_load($nid);
$node->body[LANGUAGE_NONE][0]['value'] = $this->generateFileMarkup($fid, 2);
$node->body[LANGUAGE_NONE][0]['value'] = $this->generateJsonTokenMarkup($fid, 2);
$node->revision = TRUE;
node_save($node);
......@@ -163,7 +97,7 @@ class MediaFileUsageTest extends MediaTestHelper {
// Create a new revision that has the file on it. File usage will be 5.
$node = node_load($nid);
$node->body[LANGUAGE_NONE][0]['value'] = $this->generateFileMarkup($fid, 1);
$node->body[LANGUAGE_NONE][0]['value'] = $this->generateJsonTokenMarkup($fid, 1);
$node->revision = TRUE;
node_save($node);
......@@ -194,7 +128,7 @@ class MediaFileUsageTest extends MediaTestHelper {
// Create a new revision with the file on it twice. File usage will be 4.
$node = node_load($nid);
$node->body[LANGUAGE_NONE][0]['value'] = $this->generateFileMarkup($fid, 2);
$node->body[LANGUAGE_NONE][0]['value'] = $this->generateJsonTokenMarkup($fid, 2);
$node->revision = TRUE;
node_save($node);
......@@ -206,7 +140,7 @@ class MediaFileUsageTest extends MediaTestHelper {
// Re-save current revision with file on it once instead of twice. File
// usage will be 3.
$node = node_load($nid);
$node->body[LANGUAGE_NONE][0]['value'] = $this->generateFileMarkup($fid, 1);
$node->body[LANGUAGE_NONE][0]['value'] = $this->generateJsonTokenMarkup($fid, 1);
$saved_vid = $node->vid;
node_save($node);
......
<?php
/**
* @file
* Tests for ensuring media macros render properly.
*/
/**
* Defines media macro test cases.
*/
class MediaWysiwygOverridesTest extends MediaTestHelper {
/**
* Provide test information.
*/
public static function getInfo() {
return array(
'name' => t('Media wysiwyg overrides'),
'description' => t('Tests that overriden attributes display correct.'),
'group' => t('Media'),
'dependencies' => array('token'),
);
}
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_html][status]' => FALSE,
);
$this->drupalPost('admin/config/content/formats/filtered_html', $edit, t('Save configuration'));
}
/**
* Test image media overrides.
*/
public function testAttributeOverrides() {
$files = $this->drupalGetTestFiles('image');
$file = file_save($files[0]);
// Create a node to test with.
$nid = $this->createNode($file->fid);
$this->drupalGet('node/' . $nid);
$this->assertRaw('height="100" width="100"', t('Image displays with default attributes.'));
// Create a node with a style attribute.
$attributes = array(
'style' => 'float: left; width: 50px;',
);
$nid = $this->createNode($file->fid, $attributes);
$this->drupalGet('node/' . $nid);
$this->assertRaw(drupal_attributes($attributes), t('Image displays with overriden attributes.'));
// Create a node with overriden alt/title attributes.
$attributes = array(
'alt' => $this->randomName(),
'title' => $this->randomName(),
);
$nid = $this->createNode($file->fid, $attributes);
$this->drupalGet('node/' . $nid);
$this->assertRaw(drupal_attributes($attributes), t('Image displays with alt/title set as attributes.'));
// Create a node with overriden alt/title fields.
$fields = $attributes = array();
$attributes['alt'] = $fields['field_file_image_alt_text[und][0][value]'] = $this->randomName();
$attributes['title'] = $fields['field_file_image_title_text[und][0][value]'] = $this->randomName();
$nid = $this->createNode($file->fid, array(), $fields);
$this->drupalGet('node/' . $nid);
// Ensure that the alt/title from attributes display.
$this->assertRaw(drupal_attributes($attributes), t('Image displays with alt/title set as fields.'));
// Create a node with overriden alt/title fields as well as attributes.
$attributes = array(
'alt' => $this->randomName(),
'title' => $this->randomName(),
);
$fields = array(
'field_file_image_alt_text[und][0][value]' => $this->randomName(),
'field_file_image_title_text[und][0][value]' => $this->randomName(),
);
$nid = $this->createNode($file->fid, $attributes, $fields);
$this->drupalGet('node/' . $nid);
// Ensure that the alt/title from attributes display rather the field ones.
$this->assertRaw(drupal_attributes($attributes), t('Image displays with alt/title set as attributes overriding field values.'));
}
}
......@@ -14,6 +14,88 @@ class MediaTestHelper extends DrupalWebTestCase {
* Enable media and file entity modules for testing.
*/
public function setUp() {
parent::setUp(array('media', 'file_entity'));
$modules = func_get_args();
if (isset($modules[0]) && is_array($modules[0])) {
$modules = $modules[0];
}
$modules[] = 'media';
parent::setUp($modules);
}
/**
* Generates markup to be inserted for a file.
*
* This is a PHP version of InsertMedia.insert() from js/wysiwyg-media.js.
*
* @param int $fid
* Drupal file id
* @param int $count
* Quantity of markup to insert
* @param array $attributes
* Extra attributes to insert.
* @param array $fields
* Extra field values to insert.
*
* @return string
* Filter markup.
*/
protected function generateJsonTokenMarkup($fid, $count = 1, array $attributes = array(), array $fields = array()) {
$markup = '';
// Merge default atttributes.
$attributes += array(
'height' => 100,
'width' => 100,
'classes' => 'media-element file_preview',
);
// Build the data that is used in a media tag.
$data = array(
'fid' => $fid,
'type' => 'media',
'view_mode' => 'preview',
'attributes' => $attributes,
'fields' => $fields,
);
// Create the file usage markup.
for ($i = 1; $i <= $count; $i++) {
$markup .= '<p>[[' . drupal_json_encode($data) . ']]</p>';
}
return $markup;
}
/**
* Utility function to create a test node.
*
* @param int $fid
* Create the node with media markup in the body field
* @param array $attributes
* Extra attributes to insert to the file.
* @param array $fields
* Extra field values to insert.
*
* @return int
* Returns the node id
*/
protected function createNode($fid = FALSE, array $attributes = array(), array $fields = array()) {
$markup = '';
if (! empty($fid)) {
$markup = $this->generateJsonTokenMarkup($fid, 1, $attributes, $fields);
}
// Create an article node with file markup in the body field.
$edit = array(
'title' => $this->randomName(8),
'body[und][0][value]' => $markup,
);
// Save the article node. First argument is the URL, then the value array
// and the third is the label the button that should be "clicked".
$this->drupalPost('node/add/article', $edit, t('Save'));
// Get the article node that was saved by the unique title.
$node = $this->drupalGetNodeByTitle($edit['title']);
return $node->nid;
}
}
......@@ -68,7 +68,7 @@ function media_include_browser_js() {
}
}
// Add wysiwyg-specific settings.
$settings = array('wysiwyg_allowed_attributes' => variable_get('media__wysiwyg_allowed_attributes', array('height', 'width', 'hspace', 'vspace', 'border', 'align', 'style', 'class', 'id', 'usemap', 'data-picture-group', 'data-picture-align')));
$settings = array('wysiwyg_allowed_attributes' => variable_get('media__wysiwyg_allowed_attributes', _media_wysiwyg_allowed_attributes_default()));
drupal_add_js(array('media' => $settings), 'setting');
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment