diff --git a/includes/media.filter.inc b/includes/media.filter.inc index 32424df..f76693d 100644 --- a/includes/media.filter.inc +++ b/includes/media.filter.inc @@ -173,39 +173,55 @@ function media_token_to_markup($match, $wysiwyg = FALSE) { // Track the fid of this file in the {media_filter_usage} table. media_filter_track_usage($file->fid); - $attributes = is_array($tag_info['attributes']) ? $tag_info['attributes'] : array(); - $attribute_whitelist = media_variable_get('wysiwyg_allowed_attributes'); - $settings['attributes'] = array_intersect_key($attributes, array_flip($attribute_whitelist)); - - // Many media formatters will want to apply width and height independently - // of the style attribute or the corresponding HTML attributes, so pull - // these two out into top-level settings. Different WYSIWYG editors have - // different behavior with respect to whether they store user-specified - // dimensions in the HTML attributes or the style attribute, so check both. - // Per http://www.w3.org/TR/html5/the-map-element.html#attr-dim-width, the - // HTML attributes are merely hints: CSS takes precedence. - if (isset($settings['attributes']['style'])) { - $css_properties = media_parse_css_declarations($settings['attributes']['style']); - foreach (array('width', 'height') as $dimension) { - if (isset($css_properties[$dimension]) && substr($css_properties[$dimension], -2) == 'px') { - $settings[$dimension] = substr($css_properties[$dimension], 0, -2); - } - elseif (isset($settings['attributes'][$dimension])) { - $settings[$dimension] = $settings['attributes'][$dimension]; + if (!empty($tag_info['attributes']) && is_array($tag_info['attributes'])) { + $attribute_whitelist = media_variable_get('wysiwyg_allowed_attributes'); + $settings['attributes'] = array_intersect_key($tag_info['attributes'], array_flip($attribute_whitelist)); + + // Many media formatters will want to apply width and height independently + // of the style attribute or the corresponding HTML attributes, so pull + // these two out into top-level settings. Different WYSIWYG editors have + // different behavior with respect to whether they store user-specified + // dimensions in the HTML attributes or the style attribute, so check both. + // Per http://www.w3.org/TR/html5/the-map-element.html#attr-dim-width, the + // HTML attributes are merely hints: CSS takes precedence. + if (isset($settings['attributes']['style'])) { + $css_properties = media_parse_css_declarations($settings['attributes']['style']); + foreach (array('width', 'height') as $dimension) { + if (isset($css_properties[$dimension]) && substr($css_properties[$dimension], -2) == 'px') { + $settings[$dimension] = substr($css_properties[$dimension], 0, -2); + } + elseif (isset($settings['attributes'][$dimension])) { + $settings[$dimension] = $settings['attributes'][$dimension]; + } } } } - - if ($wysiwyg) { - $settings['wysiwyg'] = $wysiwyg; - } } catch (Exception $e) { watchdog('media', 'Unable to render media from %tag. Error: %error', array('%tag' => $tag, '%error' => $e->getMessage())); return ''; } - $element = media_get_file_without_label($file, $tag_info['view_mode'], $settings); + if ($wysiwyg) { + $settings['wysiwyg'] = $wysiwyg; + // If sending markup to a WYSIWYG, we need to pass the file infomation so + // that a inline macro can be generated when the WYSIWYG is detached. + // The WYSIWYG plugin is expecting this information in the format of a + // urlencoded JSON string stored in the data-file_info attribute of the + // element. + $element = media_get_file_without_label($file, $tag_info['view_mode'], $settings); + $data = drupal_json_encode(array( + 'type' => 'media', + 'fid' => $file->fid, + 'view_mode' => $tag_info['view_mode'], + )); + $element['#attributes']['data-file_info'] = urlencode($data); + $element['#attributes']['class'][] = 'media-element'; + } + else { + $element = media_get_file_without_label($file, $tag_info['view_mode'], $settings); + } + drupal_alter('media_token_to_markup', $element, $tag_info, $settings); return drupal_render($element); } @@ -410,6 +426,10 @@ function media_get_file_without_label($file, $view_mode, $settings = array()) { } } + if (!empty($element['#attributes']['class']) && !is_array($element['#attributes']['class'])) { + $element['#attributes']['class'] = array($element['#attributes']['class']); + } + return $element; } diff --git a/js/media.format_form.js b/js/media.format_form.js index 446cb54..64244e1 100644 --- a/js/media.format_form.js +++ b/js/media.format_form.js @@ -23,7 +23,7 @@ Drupal.behaviors.mediaFormatForm = { $('' + Drupal.t('Submit') + '').appendTo($('#media-format-form')).bind('click', Drupal.media.formatForm.submit); $('' + Drupal.t('Cancel') + '').appendTo($('#media-format-form')).bind('click', Drupal.media.formatForm.submit); - if (Drupal.settings.media_format_form.autosubmit) { + if (Drupal.settings.media_format_form && Drupal.settings.media_format_form.autosubmit) { $('.button.fake-ok').click(); } } diff --git a/js/wysiwyg-media.js b/js/wysiwyg-media.js index 97697f0..7682ca5 100644 --- a/js/wysiwyg-media.js +++ b/js/wysiwyg-media.js @@ -6,158 +6,131 @@ (function ($) { -Drupal.media = Drupal.media || {}; +/** + * Defining InsertMedia object to manage the sequence of actions involved in + * inserting a media element into the WYSIWYG. + * Keeps track of the WYSIWYG instance id. + */ +var InsertMedia = function (instance_id) { + this.instanceId = instance_id; + return this; +}; -// Define the behavior. -Drupal.wysiwyg.plugins.media = { +InsertMedia.prototype = { /** - * Initializes the tag map. + * Prompt user to select a media item with the media browser. + * + * @param settings + * Settings object to pass on to the media browser. + * TODO: Determine if this is actually necessary. */ - initializeTagMap: function () { - if (typeof Drupal.settings.tagmap == 'undefined') { - Drupal.settings.tagmap = { }; - } + prompt: function (settings) { + Drupal.media.popups.mediaBrowser($.proxy(this, 'onSelect'), settings); }, + /** - * Execute the button. - * @TODO: Debug calls from this are never called. What's its function? + * On selection of a media item, display item's display configuration form. */ - invoke: function (data, settings, instanceId) { - if (data.format == 'html') { - Drupal.media.popups.mediaBrowser(function (mediaFiles) { - Drupal.wysiwyg.plugins.media.mediaBrowserOnSelect(mediaFiles, instanceId); - }, settings['global']); - } + onSelect: function (media_files) { + this.mediaFile = media_files[0]; + Drupal.media.popups.mediaStyleSelector(this.mediaFile, $.proxy(this, 'insert'), {}); }, /** - * Respond to the mediaBrowser's onSelect event. - * @TODO: Debug calls from this are never called. What's its function? + * When display config has been set, insert the placeholder markup into the + * wysiwyg and generate its corresponding json macro pair to be added to the + * tagmap. */ - mediaBrowserOnSelect: function (mediaFiles, instanceId) { - var mediaFile = mediaFiles[0]; - var options = {}; - Drupal.media.popups.mediaStyleSelector(mediaFile, function (formattedMedia) { - Drupal.wysiwyg.plugins.media.insertMediaFile(mediaFile, formattedMedia.type, formattedMedia.html, formattedMedia.options, Drupal.wysiwyg.instances[instanceId]); - }, options); - - return; - }, + insert: function (formatted_media) { + var element = create_element(formatted_media.html, { + fid: this.mediaFile.fid, + view_mode: formatted_media.type + }); - insertMediaFile: function (mediaFile, viewMode, formattedMedia, options, wysiwygInstance) { + var markup = outerHTML(element), + macro = create_macro(element); - this.initializeTagMap(); - // @TODO: the folks @ ckeditor have told us that there is no way - // to reliably add wrapper divs via normal HTML. - // There is some method of adding a "fake element" - // But until then, we're just going to embed to img. - // This is pretty hacked for now. - // - var imgElement = $(this.stripDivs(formattedMedia)); - this.addImageAttributes(imgElement, mediaFile.fid, viewMode, options); - - var toInsert = this.outerHTML(imgElement); - // Create an inline tag - var inlineTag = Drupal.wysiwyg.plugins.media.createTag(imgElement); - // Add it to the tag map in case the user switches input formats - Drupal.settings.tagmap[inlineTag] = toInsert; - wysiwygInstance.insert(toInsert); - }, + // Insert placeholder markup into wysiwyg. + Drupal.wysiwyg.instances[this.instanceId].insert(markup); - /** - * Gets the HTML content of an element - * - * @param jQuery element - */ - outerHTML: function (element) { - return $('
').append( element.eq(0).clone() ).html(); - }, + // Store macro/markup pair in the tagmap. + ensure_tagmap(); + Drupal.settings.tagmap[macro] = markup; + } + +}; - addImageAttributes: function (imgElement, fid, view_mode, additional) { - // imgElement.attr('fid', fid); - // imgElement.attr('view_mode', view_mode); - // Class so we can find this image later. - imgElement.addClass('media-image'); - this.forceAttributesIntoClass(imgElement, fid, view_mode, additional); - if (additional) { - for (k in additional) { - if (additional.hasOwnProperty(k)) { - if (k === 'attr') { - imgElement.attr(k, additional[k]); - } - } - } - } - }, + +/** + * Register the plugin with WYSIWYG. + */ +Drupal.wysiwyg.plugins.media = { /** - * Due to problems handling wrapping divs in ckeditor, this is needed. - * - * Going forward, if we don't care about supporting other editors - * we can use the fakeobjects plugin to ckeditor to provide cleaner - * transparency between what Drupal will output
- * instead of just , for now though, we're going to remove all the stuff surrounding the images. - * - * @param String formattedMedia - * Element containing the image + * Execute the button. * - * @return HTML of tag inside formattedMedia + * @param data + * An object containing data about the current selection: + * - format: 'html' when the passed data is HTML content, 'text' when the + * passed data is plain-text content. + * - node: When 'format' is 'html', the focused DOM element in the editor. + * - content: The textual representation of the focused/selected editor + * content. + * @param settings + * The plugin settings, as provided in the plugin's PHP include file. + * @param instanceId + * The ID of the current editor instance. */ - stripDivs: function (formattedMedia) { - // Check to see if the image tag has divs to strip - var stripped = null; - if ($(formattedMedia).is('img')) { - stripped = this.outerHTML($(formattedMedia)); - } else { - stripped = this.outerHTML($('img', $(formattedMedia))); + invoke: function (data, settings, instanceId) { + if (data.format == 'html') { + var insert = new InsertMedia(instanceId); + insert.prompt(settings.global); } - // This will fail if we pass the img tag without anything wrapping it, like we do when re-enabling WYSIWYG - return stripped; }, /** * Attach function, called when a rich text editor loads. - * This finds all [[tags]] and replaces them with the html - * that needs to show in the editor. * + * This finds all JSON macros and replaces them with the HTML placeholder + * that will show in the editor. */ attach: function (content, settings, instanceId) { - var matches = content.match(/\[\[.*?\]\]/g); - this.initializeTagMap(); - var tagmap = Drupal.settings.tagmap; + ensure_tagmap(); + + var tagmap = Drupal.settings.tagmap, + matches = content.match(/\[\[.*?\]\]/g), + media_definition; + if (matches) { - var inlineTag = ""; - for (i = 0; i < matches.length; i++) { - inlineTag = matches[i]; - if (tagmap[inlineTag]) { - // This probably needs some work... - // We need to somehow get the fid propogated here. - // We really want to - var tagContent = tagmap[inlineTag]; - var mediaMarkup = this.stripDivs(tagContent); // THis is
.. - - var _tag = inlineTag; - _tag = _tag.replace('[[',''); - _tag = _tag.replace(']]',''); + for (var index in matches) { + var macro = matches[index]; + + if (tagmap[macro]) { + var media_json = macro.replace('[[', '').replace(']]', ''); + + // Make sure that the media JSON is valid. try { - mediaObj = JSON.parse(_tag); + media_definition = JSON.parse(media_json); } - catch(err) { - mediaObj = null; + catch (err) { + media_definition = null; } - if(mediaObj) { - var imgElement = $(mediaMarkup); - this.addImageAttributes(imgElement, mediaObj.fid, mediaObj.view_mode); - var toInsert = this.outerHTML(imgElement); - content = content.replace(inlineTag, toInsert); + + if (media_definition) { + // Apply attributes. + var element = create_element(tagmap[macro], media_definition); + var markup = outerHTML(element); + + content = content.replace(macro, markup); } } else { - debug.debug("Could not find content for " + inlineTag); + debug.debug("Could not find content for " + macro); } } } + return content; }, @@ -165,221 +138,124 @@ Drupal.wysiwyg.plugins.media = { * Detach function, called when a rich text editor detaches */ detach: function (content, settings, instanceId) { - // Replace all Media placeholder images with the appropriate inline json - // string. Using a regular expression instead of jQuery manipulation to - // prevent