diff --git a/includes/media.filter.inc b/includes/media.filter.inc index 64b72a3..a353d8e 100644 --- a/includes/media.filter.inc +++ b/includes/media.filter.inc @@ -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; @@ -379,6 +378,7 @@ function media_token_to_markup($match, $wysiwyg = FALSE) { // Display the field elements. $element = array(); $element['content']['file'] = media_get_file_without_label($file, $tag_info['view_mode'], $settings); + // Overwrite or set the file #alt attribute if it has been set in this // instance. if (!empty($element['content']['file']['#attributes']['alt'])) { @@ -392,6 +392,7 @@ function media_token_to_markup($match, $wysiwyg = FALSE) { field_attach_prepare_view('file', array($file->fid => $file), $tag_info['view_mode']); entity_prepare_view('file', array($file->fid => $file)); $element['content'] += field_attach_view('file', $file, $tag_info['view_mode']); + if (count(element_children($element['content'])) > 1) { // Add surrounding divs to group them together. // We dont want divs when there are no additional fields to allow files @@ -404,6 +405,7 @@ function media_token_to_markup($match, $wysiwyg = FALSE) { ); } } + drupal_alter('media_token_to_markup', $element, $tag_info, $settings); return drupal_render($element); } @@ -668,18 +670,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 structures 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; + } } } diff --git a/js/media.filter.js b/js/media.filter.js index 2e4ceda..d58f70c 100644 --- a/js/media.filter.js +++ b/js/media.filter.js @@ -14,36 +14,33 @@ * @param content */ replaceTokenWithPlaceholder: function(content) { - var tagmap = Drupal.media.filter.ensure_tagmap(), - matches = content.match(/\[\[.*?\]\]/g), - media_definition, - id = 0; - - if (matches) { - var i = 1; - for (var macro in tagmap) { - var index = matches.indexOf(macro); - if (index !== -1) { - var media_json = macro.replace('[[', '').replace(']]', ''); - - // Make sure that the media JSON is valid. - try { - media_definition = JSON.parse(media_json); - } - catch (err) { - media_definition = null; - } - if (media_definition) { - // Apply attributes. - 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)); - } + var matches = content.match(/\[\[.*?\]\]/g); + + if (!!matches) { + for (i in matches) { + var match = matches[i]; + var media_json = match.replace('[[', '').replace(']]', ''); + + // Ensure that the media JSON is valid. + try { + var media_definition = JSON.parse(media_json); + + // Create the element. + var element = document.createElement(media_definition.tagName); + element.src = media_definition.src; + + // Apply attributes. + var element = Drupal.media.filter.create_element(element, media_definition); + var markup = Drupal.media.filter.outerHTML(element); + + content = content.replace(match, Drupal.media.filter.getWrapperStart(i) + markup + Drupal.media.filter.getWrapperEnd(i)); + } + catch (err) { + // TODO: Error logging. } - i++; } } + return content; }, @@ -52,20 +49,26 @@ * @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++; - } + Drupal.settings.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, el) { + // TODO zero-index wrapper indices. + var startTag = Drupal.media.filter.getWrapperStart(i + 1), + endTag = Drupal.media.filter.getWrapperEnd(i + 1), + macro = Drupal.media.filter.create_macro($(el)); + + Drupal.settings.tagmap[macro] = el.outerHTML; + + content = content + .replace(el.outerHTML, macro) + .replace(startTag, '') + .replace(endTag, ''); + }); + return content; }, @@ -182,12 +185,16 @@ file_info.attributes = {}; // Extract whitelisted attributes. - $.each(Drupal.media.filter.allowed_attributes, function(i, a) { + $.each(Drupal.media.filter.allowed_attributes(), function(i, a) { if (value = element.attr(a)) { file_info.attributes[a] = value; } }); delete(file_info.attributes['data-file_info']); + + // Set tagName and src to rebuild later. + file_info.tagName = element[0].tagName; + file_info.src = element[0].src; } return file_info; diff --git a/media.module b/media.module index f2720cb..8eca84e 100644 --- a/media.module +++ b/media.module @@ -1292,3 +1292,27 @@ 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 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', + ); +} diff --git a/wysiwyg_plugins/media.inc b/wysiwyg_plugins/media.inc index d90b79f..611ee60 100644 --- a/wysiwyg_plugins/media.inc +++ b/wysiwyg_plugins/media.inc @@ -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'); }