123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349 |
- /**
- * @file
- * Attach Media ckeditor behaviors.
- */
- (function ($) {
- Drupal.media = Drupal.media || {};
- Drupal.settings.ckeditor.plugins['media'] = {
- /**
- * Initializes the tag map.
- */
- initializeTagMap: function () {
- if (typeof Drupal.settings.tagmap == 'undefined') {
- Drupal.settings.tagmap = { };
- }
- },
- /**
- * Execute the button.
- */
- invoke: function (data, settings, instanceId) {
- if (data.format == 'html') {
- Drupal.media.popups.mediaBrowser(function (mediaFiles) {
- Drupal.settings.ckeditor.plugins['media'].mediaBrowserOnSelect(mediaFiles, instanceId);
- }, settings['global']);
- }
- },
- /**
- * Respond to the mediaBrowser's onSelect event.
- */
- mediaBrowserOnSelect: function (mediaFiles, instanceId) {
- var mediaFile = mediaFiles[0];
- var options = {};
- Drupal.media.popups.mediaStyleSelector(mediaFile, function (formattedMedia) {
- Drupal.settings.ckeditor.plugins['media'].insertMediaFile(mediaFile, formattedMedia.type, formattedMedia.html, formattedMedia.options, CKEDITOR.instances[instanceId]);
- }, options);
- return;
- },
- insertMediaFile: function (mediaFile, viewMode, formattedMedia, options, ckeditorInstance) {
- 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.settings.ckeditor.plugins['media'].createTag(imgElement);
- // Add it to the tag map in case the user switches input formats
- Drupal.settings.tagmap[inlineTag] = toInsert;
- ckeditorInstance.insertHtml(toInsert);
- },
- /**
- * Gets the HTML content of an element
- *
- * @param jQuery element
- */
- outerHTML: function (element) {
- return $('<div>').append( element.eq(0).clone() ).html();
- },
- addImageAttributes: function (imgElement, fid, view_mode, additional) {
- imgElement.addClass('media-image');
- this.forceAttributesIntoClass(imgElement, fid, view_mode, additional);
- },
- /**
- * 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 <div class="field..."><img></div>
- * instead of just <img>, for now though, we're going to remove all the stuff surrounding the images.
- *
- * @param String formattedMedia
- * Element containing the image
- *
- * @return HTML of <img> tag inside formattedMedia
- */
- 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)));
- }
- // This will fail if we pass the img tag without anything wrapping it, like we do when re-enabling ckeditor
- 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.
- *
- */
- attach: function (content, settings, instanceId) {
- var matches = content.match(/\[\[.*?\]\]/g);
- this.initializeTagMap();
- var tagmap = Drupal.settings.tagmap;
- 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 <div>..<img>
- var _tag = inlineTag;
- _tag = _tag.replace('[[','');
- _tag = _tag.replace(']]','');
- mediaObj = JSON.parse(_tag);
- var imgElement = $(mediaMarkup);
- this.addImageAttributes(imgElement, mediaObj.fid, mediaObj.view_mode);
- var toInsert = this.outerHTML(imgElement);
- content = content.replace(inlineTag, toInsert);
- }
- else {
- debug.debug("Could not find content for " + inlineTag);
- }
- }
- }
- return content;
- },
- /**
- * Detach function, called when a rich text editor detaches
- */
- detach: function (content, settings, instanceId) {
- var content = $('<div>' + content + '</div>');
- $('img.media-image',content).each(function (elem) {
- var tag = Drupal.settings.ckeditor.plugins['media'].createTag($(this));
- $(this).replaceWith(tag);
- var newContent = content.html();
- var tagContent = $('<div></div>').append($(this)).html();
- Drupal.settings.tagmap[tag] = tagContent;
- });
- return content.html();
- },
- /**
- * @param jQuery imgNode
- * Image node to create tag from
- */
- createTag: function (imgNode) {
- // Currently this is the <img> itself
- // Collect all attribs to be stashed into tagContent
- var mediaAttributes = {};
- var imgElement = imgNode[0];
- var sorter = [];
- // @todo: this does not work in IE, width and height are always 0.
- for (i=0; i< imgElement.attributes.length; i++) {
- var attr = imgElement.attributes[i];
- if (attr.specified == true) {
- if (attr.name !== 'class') {
- sorter.push(attr);
- }
- else {
- // Exctract expando properties from the class field.
- var attributes = this.getAttributesFromClass(attr.value);
- for (var name in attributes) {
- if (attributes.hasOwnProperty(name)) {
- var value = attributes[name];
- if (value.type && value.type === 'attr') {
- sorter.push(value);
- }
- }
- }
- }
- }
- }
- sorter.sort(this.sortAttributes);
- for (var prop in sorter) {
- mediaAttributes[sorter[prop].name] = sorter[prop].value;
- }
- // The following 5 ifs are dedicated to IE7
- // If the style is null, it is because IE7 can't read values from itself
- if (jQuery.browser.msie && jQuery.browser.version == '7.0') {
- if (mediaAttributes.style === "null") {
- var imgHeight = imgNode.css('height');
- var imgWidth = imgNode.css('width');
- mediaAttributes.style = {
- height: imgHeight,
- width: imgWidth
- }
- if (!mediaAttributes['width']) {
- mediaAttributes['width'] = imgWidth;
- }
- if (!mediaAttributes['height']) {
- mediaAttributes['height'] = imgHeight;
- }
- }
- // If the attribute width is zero, get the CSS width
- if (Number(mediaAttributes['width']) === 0) {
- mediaAttributes['width'] = imgNode.css('width');
- }
- // IE7 does support 'auto' as a value of the width attribute. It will not
- // display the image if this value is allowed to pass through
- if (mediaAttributes['width'] === 'auto') {
- delete mediaAttributes['width'];
- }
- // If the attribute height is zero, get the CSS height
- if (Number(mediaAttributes['height']) === 0) {
- mediaAttributes['height'] = imgNode.css('height');
- }
- // IE7 does support 'auto' as a value of the height attribute. It will not
- // display the image if this value is allowed to pass through
- if (mediaAttributes['height'] === 'auto') {
- delete mediaAttributes['height'];
- }
- }
- // Remove elements from attribs using the blacklist
- for (var blackList in Drupal.settings.media.blacklist) {
- delete mediaAttributes[Drupal.settings.media.blacklist[blackList]];
- }
- tagContent = {
- "type": 'media',
- // @todo: This will be selected from the format form
- "view_mode": attributes['view_mode'].value,
- "fid" : attributes['fid'].value,
- "attributes": mediaAttributes
- };
- return '[[' + JSON.stringify(tagContent) + ']]';
- },
- /**
- * Forces custom attributes into the class field of the specified image.
- *
- * Due to a bug in some versions of Firefox
- * (http://forums.mozillazine.org/viewtopic.php?f=9&t=1991855), the
- * custom attributes used to share information about the image are
- * being stripped as the image markup is set into the rich text
- * editor. Here we encode these attributes into the class field so
- * the data survives.
- *
- * @param imgElement
- * The image
- * @fid
- * The file id.
- * @param view_mode
- * The view mode.
- * @param additional
- * Additional attributes to add to the image.
- */
- forceAttributesIntoClass: function (imgElement, fid, view_mode, additional) {
- var wysiwyg = imgElement.attr('wysiwyg');
- if (wysiwyg) {
- imgElement.addClass('attr__wysiwyg__' + wysiwyg);
- }
- var format = imgElement.attr('format');
- if (format) {
- imgElement.addClass('attr__format__' + format);
- }
- var typeOf = imgElement.attr('typeof');
- if (typeOf) {
- imgElement.addClass('attr__typeof__' + typeOf);
- }
- if (fid) {
- imgElement.addClass('img__fid__' + fid);
- }
- if (view_mode) {
- imgElement.addClass('img__view_mode__' + view_mode);
- }
- if (additional) {
- for (var name in additional) {
- if (additional.hasOwnProperty(name)) {
- if (name !== 'alt') {
- imgElement.addClass('attr__' + name + '__' + additional[name]);
- }
- }
- }
- }
- },
- /**
- * Retrieves encoded attributes from the specified class string.
- *
- * @param classString
- * A string containing the value of the class attribute.
- * @return
- * An array containing the attribute names as keys, and an object
- * with the name, value, and attribute type (either 'attr' or
- * 'img', depending on whether it is an image attribute or should
- * be it the attributes section)
- */
- getAttributesFromClass: function (classString) {
- var actualClasses = [];
- var otherAttributes = [];
- var classes = classString.split(' ');
- var regexp = new RegExp('^(attr|img)__([^\S]*)__([^\S]*)$');
- for (var index = 0; index < classes.length; index++) {
- var matches = classes[index].match(regexp);
- if (matches && matches.length === 4) {
- otherAttributes[matches[2]] = {
- name: matches[2],
- value: matches[3],
- type: matches[1]
- };
- }
- else {
- actualClasses.push(classes[index]);
- }
- }
- if (actualClasses.length > 0) {
- otherAttributes['class'] = {
- name: 'class',
- value: actualClasses.join(' '),
- type: 'attr'
- };
- }
- return otherAttributes;
- },
- sortAttributes: function (a, b) {
- var nameA = a.name.toLowerCase();
- var nameB = b.name.toLowerCase();
- if (nameA < nameB) {
- return -1;
- }
- if (nameA > nameB) {
- return 1;
- }
- return 0;
- }
- };
- })(jQuery);
|