diff --git a/js/media.filter.js b/js/media.filter.js index a48d258..74c013c 100644 --- a/js/media.filter.js +++ b/js/media.filter.js @@ -41,8 +41,8 @@ } // Apply attributes. - var element = Drupal.media.filter.create_element(media, media_definition); - var markup = Drupal.media.filter.outerHTML(element); + var element = Drupal.media.filter.createElement(media, media_definition); + var markup = Drupal.media.filter.safeMarkup(element); content = content.replace(match, markup); } @@ -62,15 +62,16 @@ 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) { - var macro = Drupal.media.filter.create_macro($(el)); + $('.media-element', content).each(function(i, element) { + var markup = Drupal.media.filter.safeMarkup($(element)); + macro = Drupal.media.filter.createMacro($(element)); // Store the macro => html for more efficient rendering in // replaceTokenWithPlaceholder(). - Drupal.settings.tagmap[macro] = el.outerHTML; + Drupal.settings.tagmap[macro] = markup; // Replace the media element with its macro. - content = content.replace(el.outerHTML, macro); + content = content.replace(markup, macro); }); return content; @@ -86,32 +87,53 @@ * @return The registered element. */ registerNewElement: function (formattedMedia, fid) { - var element = Drupal.media.filter.create_element(formattedMedia.html, { + var element = Drupal.media.filter.createElement(formattedMedia.html, { fid: fid, view_mode: formattedMedia.type, attributes: formattedMedia.options }); - var markup = Drupal.media.filter.outerHTML(element), - macro = Drupal.media.filter.create_macro(element); + var markup = Drupal.media.filter.safeMarkup(element), + macro = Drupal.media.filter.createMacro(element); // Store macro/markup pair in the tagmap. Drupal.media.filter.ensure_tagmap(); Drupal.settings.tagmap[macro] = markup; - return element; + return markup; + }, + + /** + * Returns alt and title field values for use as html attributes. + * + * @param options (array) Options passed through a popup form submission. + */ + parseAttributeFields: function(options) { + var attributes = []; + + for (field in options) { + if (field.match('image_alt')) { + attributes['alt'] = options[field]; + } + + if (field.match('image_title')) { + attributes['title'] = options[field]; + } + } + + return attributes; }, /** - * Serializes file information as a url-encoded JSON object and stores it as a - * data attribute on the html element. + * Serializes file information as a url-encoded JSON object and stores it + * as a data attribute on the html element. * * @param html (string) * A html element to be used to represent the inserted media element. * @param info (object) * A object containing the media file information (fid, view_mode, etc). */ - create_element: function (html, info) { + createElement: function (html, info) { if ($('
').append(html).text().length === html.length) { // Element is not an html tag. Surround it in a span element // so we can pass the file attributes. @@ -137,7 +159,7 @@ // Adding media-element class so we can find markup element later. var classes = ['media-element']; - if(info.view_mode){ + if (info.view_mode) { classes.push('file-' + info.view_mode.replace(/_/g, '-')); } element.addClass(classes.join(' ')); @@ -151,8 +173,8 @@ * @param element (jQuery object) * A media element with attached serialized file info. */ - create_macro: function (element) { - var file_info = Drupal.media.filter.extract_file_info(element); + createMacro: function (element) { + var file_info = Drupal.media.filter.extractFileInfo(element); if (file_info) { return '[[' + JSON.stringify(file_info) + ']]'; } @@ -165,7 +187,7 @@ * @param element (jQuery object) * A media element with attached serialized file info. */ - extract_file_info: function (element) { + extractFileInfo: function (element) { var file_json = $.data(element, 'file_info') || element.data('file_info'), file_info, value; @@ -202,7 +224,28 @@ * @param element (jQuery object) */ outerHTML: function (element) { - return $('
').append(element.eq(0).clone()).html(); + return element[0].outerHTML || $('
').append(element.eq(0).clone()).html(); + }, + + /** + * Parses an element's markup and returns it with its attributes in + * alphabetical order. Use as a wrapper when outerHTML is needed. + * + * @param element (jQuery object) The element to modify. + * + * @see http://dev.ckeditor.com/ticket/1810 + */ + safeMarkup: function(element) { + var markup = Drupal.media.filter.outerHTML(element); + + // Parse out and sort the element's attributes. + var attrs = markup.match(/([^\s]+?=".*?")/gi).sort(); + + // Create the media element markup with the sorted attributes. + var media = document.createElement($(markup)[0].tagName); + media = Drupal.media.filter.outerHTML($(media)).replace(/\>/, ' ' + attrs.join(' ') + '>'); + + return media; }, /** @@ -217,8 +260,8 @@ */ getWysiwygHTML: function (element) { // Create the markup and the macro. - var markup = Drupal.media.filter.outerHTML(element), - macro = Drupal.media.filter.create_macro(element); + var markup = Drupal.media.filter.safeMarkup(element), + macro = Drupal.media.filter.createMacro(element); // Store macro/markup in the tagmap. Drupal.media.filter.ensure_tagmap(); @@ -247,7 +290,7 @@ */ allowed_attributes: function () { Drupal.settings.wysiwyg_allowed_attributes = Drupal.settings.wysiwyg_allowed_attributes || ['height', 'width', 'hspace', 'vspace', 'border', 'align', 'style', 'alt', 'title', 'class', 'id', 'usemap']; - return Drupal.settings.wysiwyg_allowed_attributes; + return Drupal.settings.wysiwyg_allowed_attributes.sort(); } } })(jQuery); diff --git a/js/wysiwyg-media.js b/js/wysiwyg-media.js index ac5bf4d..44c6508 100644 --- a/js/wysiwyg-media.js +++ b/js/wysiwyg-media.js @@ -42,7 +42,7 @@ Drupal.wysiwyg.plugins.media = { var insert = new InsertMedia(instanceId); if (this.isNode(data.node)) { // Change the view mode for already-inserted media. - var media_file = Drupal.media.filter.extract_file_info($(data.node)); + var media_file = Drupal.media.filter.extractFileInfo($(data.node)); insert.onSelect([media_file]); } else { @@ -109,12 +109,15 @@ InsertMedia.prototype = { * tagmap. */ insert: function (formatted_media) { - var element = Drupal.media.filter.create_element(formatted_media.html, { + var attributes = Drupal.media.filter.parseAttributeFields(formatted_media.options); + + var element = Drupal.media.filter.createElement(formatted_media.html, { fid: this.mediaFile.fid, view_mode: formatted_media.type, - attributes: formatted_media.options, + attributes: $.extend(this.mediaFile.attributes, attributes), fields: formatted_media.options }); + // Get the markup and register it for the macro / placeholder handling. var markup = Drupal.media.filter.getWysiwygHTML(element); @@ -143,8 +146,8 @@ function ensure_tagmap () { * * @deprecated */ -function create_element (html, info) { - return Drupal.media.filter.create_element(html, info); +function createElement (html, info) { + return Drupal.media.filter.createElement(html, info); } /** @@ -155,8 +158,8 @@ function create_element (html, info) { * * @deprecated */ -function create_macro (element) { - return Drupal.media.filter.create_macro(element); +function createMacro (element) { + return Drupal.media.filter.createMacro(element); } /** @@ -167,8 +170,8 @@ function create_macro (element) { * * @deprecated */ -function extract_file_info (element) { - return Drupal.media.filter.extract_file_info(element); +function extractFileInfo (element) { + return Drupal.media.filter.extractFileInfo(element); } /**