/** * @file * File with utilities to handle media in html editing. */ (function ($) { Drupal.media = Drupal.media || {}; /** * Utility to deal with media tokens / placeholders. */ Drupal.media.filter = { /** * Replaces media tokens with the placeholders for html editing. * @param content */ replaceTokenWithPlaceholder: function(content) { Drupal.media.filter.ensure_tagmap(); var matches = content.match(/\[\[.*?\]\]/g); if (matches) { for (var i = 0; i < matches.length; i++) { var match = matches[i]; if (match.indexOf('"type":"media"') == -1) { continue; } // Check if the macro exists in the tagmap. This ensures backwards // compatibility with existing media and is moderately more efficient // than re-building the element. var media = Drupal.settings.tagmap[match]; var media_json = match.replace('[[', '').replace(']]', ''); // Ensure that the media JSON is valid. try { var media_definition = JSON.parse(media_json); } catch (err) { // @todo: error logging. // Content should be returned to prevent an empty editor. return content; } // Re-build the media if the macro has changed from the tagmap. if (!media && media_definition.fid) { Drupal.media.filter.ensureSourceMap(); var source; if (source = Drupal.settings.mediaSourceMap[media_definition.fid]) { media = document.createElement(source.tagName); media.src = source.src; media.innerHTML = source.innerHTML; } else { // If the media element can't be found, leave it in to be resolved // by the user later. continue; } } // Apply attributes. var element = Drupal.media.filter.create_element(media, media_definition); var markup = Drupal.media.filter.outerHTML(element); // Use split and join to replace all instances of macro with markup. content = content.split(match).join(markup); } } return content; }, /** * Returns alt and title field attribute data from the corresponding fields. * * Specifically looks for file_entity module's file_image_alt_text and * file_image_title_text fields as those are by default used to store * override values for image alt and title attributes. * * @param options (array) * Options passed through a popup form submission. * @param includeFieldID (bool) * If set, the returned object will have extra keys with the IDs of the * found fields. * * If the alt or title fields were not found, their keys will be excluded * from the returned array. * * @return * An object with the following keys: * - alt: The value of the alt field. * - altField: The id of the alt field. * - title: The value of the title field. * - titleField: The id of the title field. */ parseAttributeFields: function(options, includeFieldID) { var attributes = {}; for (var field in options) { // If the field is set to false, use an empty string for output. options[field] = options[field] === false ? '' : options[field]; //if (field.match(/^field_file_image_alt_text/)) { if (field.match(new RegExp('^' + Drupal.settings.media.img_alt_field))) { attributes.alt = options[field]; if (includeFieldID) { attributes.altField = field; } } //if (field.match(/^field_file_image_title_text/)) { if (field.match(new RegExp('^' + Drupal.settings.media.img_title_field))) { attributes.title = options[field]; if (includeFieldID) { attributes.titleField = field; } } } return attributes; }, /** * Ensures changes made to fielded attributes are done on the fields too. * * This should be called when creating a macro tag from a placeholder. * * Changed made to attributes represented by fields are synced back to the * corresponding fields, if they exist. The alt/title attribute * values encoded in the macro will override the alt/title field values (set * in the Media dialog) during rendering of both WYSIWYG placeholders and * the final file entity on the server. Syncing makes changes applied to a * placeholder's alt/title attribute using native WYSIWYG tools visible in * the fields shown in the Media dialog. * * The reverse should be done when creating a placeholder from a macro tag * so changes made in the Media dialog are reflected in the placeholder's * alt and title attributes or the values there become stale and the change * appears uneffective. * * @param file_info (object) * A JSON decoded object of the file being inserted/updated. */ syncAttributesToFields: function(file_info) { if (!file_info) { file_info = {}; } if (!file_info.attributes) { file_info.attributes = {}; } if (!file_info.fields) { file_info.fields = {}; } var fields = Drupal.media.filter.parseAttributeFields(file_info.fields, true); // If the title attribute has changed, ensure the title field is updated. var titleAttr = file_info.attributes.title || false; if (fields.titleField && (titleAttr !== fields.title)) { file_info.fields[fields.titleField] = titleAttr; } // If the alt attribute has changed, ensure the alt field is updated. var altAttr = file_info.attributes.alt || false; if (fields.altField && (altAttr !== fields.alt)) { file_info.fields[fields.altField] = altAttr; } return file_info; }, /** * Replaces media elements with tokens. * * @param content (string) * The markup within the wysiwyg instance. */ replacePlaceholderWithToken: function(content) { Drupal.media.filter.ensure_tagmap(); // Locate and process all the media placeholders in the WYSIWYG 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) { // Attempt to derive a JSON macro representation of the media placeholder. // Note: Drupal 7 ships with JQuery 1.4.4, which allows $(this).attr('outerHTML') to retrieve the eement's HTML, // but many sites use JQuery update to increate this to 1.6+, which insists on $(this).prop('outerHTML). // Until the minimum jQuery is >= 1.6, we need to do this the old-school way. // See http://stackoverflow.com/questions/2419749/get-selected-elements-outer-html var markup = $(this).get(0).outerHTML; if (markup === undefined) { // Browser does not support outerHTML DOM property. Use the more expensive clone method instead. markup = $(this).clone().wrap('