350 lines
12 KiB
JavaScript
350 lines
12 KiB
JavaScript
|
|
/**
|
|
* @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);
|