bgneal@312: /** bgneal@312: * editor_plugin_src.js bgneal@312: * bgneal@312: * Copyright 2009, Moxiecode Systems AB bgneal@312: * Released under LGPL License. bgneal@312: * bgneal@312: * License: http://tinymce.moxiecode.com/license bgneal@312: * Contributing: http://tinymce.moxiecode.com/contributing bgneal@312: */ bgneal@312: bgneal@312: (function() { bgneal@442: var rootAttributes = tinymce.explode('id,name,width,height,style,align,class,hspace,vspace,bgcolor,type'), excludedAttrs = tinymce.makeMap(rootAttributes.join(',')), Node = tinymce.html.Node, bgneal@442: mediaTypes, scriptRegExp, JSON = tinymce.util.JSON, mimeTypes; bgneal@442: bgneal@442: // Media types supported by this plugin bgneal@442: mediaTypes = [ bgneal@442: // Type, clsid:s, mime types, codebase bgneal@442: ["Flash", "d27cdb6e-ae6d-11cf-96b8-444553540000", "application/x-shockwave-flash", "http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0"], bgneal@442: ["ShockWave", "166b1bca-3f9c-11cf-8075-444553540000", "application/x-director", "http://download.macromedia.com/pub/shockwave/cabs/director/sw.cab#version=8,5,1,0"], bgneal@442: ["WindowsMedia", "6bf52a52-394a-11d3-b153-00c04f79faa6,22d6f312-b0f6-11d0-94ab-0080c74c7e95,05589fa1-c356-11ce-bf01-00aa0055595a", "application/x-mplayer2", "http://activex.microsoft.com/activex/controls/mplayer/en/nsmp2inf.cab#Version=5,1,52,701"], bgneal@442: ["QuickTime", "02bf25d5-8c17-4b23-bc80-d3488abddc6b", "video/quicktime", "http://www.apple.com/qtactivex/qtplugin.cab#version=6,0,2,0"], bgneal@442: ["RealMedia", "cfcdaa03-8be4-11cf-b84b-0020afbbccfa", "audio/x-pn-realaudio-plugin", "http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0"], bgneal@442: ["Java", "8ad9c840-044e-11d1-b3e9-00805f499d93", "application/x-java-applet", "http://java.sun.com/products/plugin/autodl/jinstall-1_5_0-windows-i586.cab#Version=1,5,0,0"], bgneal@442: ["Silverlight", "dfeaf541-f3e1-4c24-acac-99c30715084a", "application/x-silverlight-2"], bgneal@442: ["Iframe"], bgneal@442: ["Video"] bgneal@442: ]; bgneal@442: bgneal@442: function toArray(obj) { bgneal@442: var undef, out, i; bgneal@442: bgneal@442: if (obj && !obj.splice) { bgneal@442: out = []; bgneal@442: bgneal@442: for (i = 0; true; i++) { bgneal@442: if (obj[i]) bgneal@442: out[i] = obj[i]; bgneal@442: else bgneal@442: break; bgneal@442: } bgneal@442: bgneal@442: return out; bgneal@442: } bgneal@442: bgneal@442: return obj; bgneal@442: }; bgneal@312: bgneal@312: tinymce.create('tinymce.plugins.MediaPlugin', { bgneal@312: init : function(ed, url) { bgneal@442: var self = this, lookup = {}, i, y, item, name; bgneal@312: bgneal@442: function isMediaImg(node) { bgneal@442: return node && node.nodeName === 'IMG' && ed.dom.hasClass(node, 'mceItemMedia'); bgneal@312: }; bgneal@312: bgneal@442: self.editor = ed; bgneal@442: self.url = url; bgneal@442: bgneal@442: // Parse media types into a lookup table bgneal@442: scriptRegExp = ''; bgneal@442: for (i = 0; i < mediaTypes.length; i++) { bgneal@442: name = mediaTypes[i][0]; bgneal@442: bgneal@442: item = { bgneal@442: name : name, bgneal@442: clsids : tinymce.explode(mediaTypes[i][1] || ''), bgneal@442: mimes : tinymce.explode(mediaTypes[i][2] || ''), bgneal@442: codebase : mediaTypes[i][3] bgneal@442: }; bgneal@442: bgneal@442: for (y = 0; y < item.clsids.length; y++) bgneal@442: lookup['clsid:' + item.clsids[y]] = item; bgneal@442: bgneal@442: for (y = 0; y < item.mimes.length; y++) bgneal@442: lookup[item.mimes[y]] = item; bgneal@442: bgneal@442: lookup['mceItem' + name] = item; bgneal@442: lookup[name.toLowerCase()] = item; bgneal@442: bgneal@442: scriptRegExp += (scriptRegExp ? '|' : '') + name; bgneal@442: } bgneal@442: bgneal@442: // Handle the media_types setting bgneal@442: tinymce.each(ed.getParam("media_types", bgneal@442: "video=mp4,m4v,ogv,webm;" + bgneal@442: "silverlight=xap;" + bgneal@442: "flash=swf,flv;" + bgneal@442: "shockwave=dcr;" + bgneal@442: "quicktime=mov,qt,mpg,mp3,mpeg;" + bgneal@442: "shockwave=dcr;" + bgneal@442: "windowsmedia=avi,wmv,wm,asf,asx,wmx,wvx;" + bgneal@442: "realmedia=rm,ra,ram;" + bgneal@442: "java=jar" bgneal@442: ).split(';'), function(item) { bgneal@442: var i, extensions, type; bgneal@442: bgneal@442: item = item.split(/=/); bgneal@442: extensions = tinymce.explode(item[1].toLowerCase()); bgneal@442: for (i = 0; i < extensions.length; i++) { bgneal@442: type = lookup[item[0].toLowerCase()]; bgneal@442: bgneal@442: if (type) bgneal@442: lookup[extensions[i]] = type; bgneal@442: } bgneal@442: }); bgneal@442: bgneal@442: scriptRegExp = new RegExp('write(' + scriptRegExp + ')\\(([^)]+)\\)'); bgneal@442: self.lookup = lookup; bgneal@442: bgneal@312: ed.onPreInit.add(function() { bgneal@442: // Allow video elements bgneal@442: ed.schema.addValidElements('object[id|style|width|height|classid|codebase|*],param[name|value],embed[id|style|width|height|type|src|*],video[*],audio[*],source[*]'); bgneal@442: bgneal@442: // Convert video elements to image placeholder bgneal@442: ed.parser.addNodeFilter('object,embed,video,audio,script,iframe', function(nodes) { bgneal@442: var i = nodes.length; bgneal@442: bgneal@442: while (i--) bgneal@442: self.objectToImg(nodes[i]); bgneal@442: }); bgneal@442: bgneal@442: // Convert image placeholders to video elements bgneal@442: ed.serializer.addNodeFilter('img', function(nodes, name, args) { bgneal@442: var i = nodes.length, node; bgneal@442: bgneal@442: while (i--) { bgneal@442: node = nodes[i]; bgneal@442: if ((node.attr('class') || '').indexOf('mceItemMedia') !== -1) bgneal@442: self.imgToObject(node, args); bgneal@442: } bgneal@442: }); bgneal@442: }); bgneal@442: bgneal@442: ed.onInit.add(function() { bgneal@442: // Display "media" instead of "img" in element path bgneal@442: if (ed.theme && ed.theme.onResolveName) { bgneal@442: ed.theme.onResolveName.add(function(theme, path_object) { bgneal@442: if (path_object.name === 'img' && ed.dom.hasClass(path_object.node, 'mceItemMedia')) bgneal@442: path_object.name = 'media'; bgneal@442: }); bgneal@442: } bgneal@442: bgneal@442: // Add contect menu if it's loaded bgneal@442: if (ed && ed.plugins.contextmenu) { bgneal@442: ed.plugins.contextmenu.onContextMenu.add(function(plugin, menu, element) { bgneal@442: if (element.nodeName === 'IMG' && element.className.indexOf('mceItemMedia') !== -1) bgneal@442: menu.add({title : 'media.edit', icon : 'media', cmd : 'mceMedia'}); bgneal@442: }); bgneal@442: } bgneal@312: }); bgneal@312: bgneal@312: // Register commands bgneal@312: ed.addCommand('mceMedia', function() { bgneal@442: var data, img; bgneal@442: bgneal@442: img = ed.selection.getNode(); bgneal@442: if (isMediaImg(img)) { bgneal@442: data = JSON.parse(ed.dom.getAttrib(img, 'data-mce-json')); bgneal@442: bgneal@442: // Add some extra properties to the data object bgneal@442: tinymce.each(rootAttributes, function(name) { bgneal@442: var value = ed.dom.getAttrib(img, name); bgneal@442: bgneal@442: if (value) bgneal@442: data[name] = value; bgneal@442: }); bgneal@442: bgneal@442: data.type = self.getType(img.className).name.toLowerCase(); bgneal@442: } bgneal@442: bgneal@442: if (!data) { bgneal@442: data = { bgneal@442: type : 'flash', bgneal@442: video: {sources:[]}, bgneal@442: params: {} bgneal@442: }; bgneal@442: } bgneal@442: bgneal@312: ed.windowManager.open({ bgneal@312: file : url + '/media.htm', bgneal@312: width : 430 + parseInt(ed.getLang('media.delta_width', 0)), bgneal@442: height : 500 + parseInt(ed.getLang('media.delta_height', 0)), bgneal@312: inline : 1 bgneal@312: }, { bgneal@442: plugin_url : url, bgneal@442: data : data bgneal@312: }); bgneal@312: }); bgneal@312: bgneal@312: // Register buttons bgneal@312: ed.addButton('media', {title : 'media.desc', cmd : 'mceMedia'}); bgneal@312: bgneal@442: // Update media selection status bgneal@442: ed.onNodeChange.add(function(ed, cm, node) { bgneal@442: cm.setActive('media', isMediaImg(node)); bgneal@312: }); bgneal@442: }, bgneal@312: bgneal@442: convertUrl : function(url, force_absolute) { bgneal@442: var self = this, editor = self.editor, settings = editor.settings, bgneal@442: urlConverter = settings.url_converter, bgneal@442: urlConverterScope = settings.url_converter_scope || self; bgneal@312: bgneal@442: if (!url) bgneal@442: return url; bgneal@312: bgneal@442: if (force_absolute) bgneal@442: return editor.documentBaseURI.toAbsolute(url); bgneal@312: bgneal@442: return urlConverter.call(urlConverterScope, url, 'src', 'object'); bgneal@312: }, bgneal@312: bgneal@312: getInfo : function() { bgneal@312: return { bgneal@312: longname : 'Media', bgneal@312: author : 'Moxiecode Systems AB', bgneal@312: authorurl : 'http://tinymce.moxiecode.com', bgneal@312: infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/media', bgneal@312: version : tinymce.majorVersion + "." + tinymce.minorVersion bgneal@312: }; bgneal@312: }, bgneal@312: bgneal@442: /** bgneal@442: * Converts the JSON data object to an img node. bgneal@442: */ bgneal@442: dataToImg : function(data, force_absolute) { bgneal@442: var self = this, editor = self.editor, baseUri = editor.documentBaseURI, sources, attrs, img, i; bgneal@312: bgneal@442: data.params.src = self.convertUrl(data.params.src, force_absolute); bgneal@312: bgneal@442: attrs = data.video.attrs; bgneal@442: if (attrs) bgneal@442: attrs.src = self.convertUrl(attrs.src, force_absolute); bgneal@442: bgneal@442: if (attrs) bgneal@442: attrs.poster = self.convertUrl(attrs.poster, force_absolute); bgneal@442: bgneal@442: sources = toArray(data.video.sources); bgneal@442: if (sources) { bgneal@442: for (i = 0; i < sources.length; i++) bgneal@442: sources[i].src = self.convertUrl(sources[i].src, force_absolute); bgneal@442: } bgneal@442: bgneal@442: img = self.editor.dom.create('img', { bgneal@442: id : data.id, bgneal@442: style : data.style, bgneal@442: align : data.align, bgneal@442: src : self.editor.theme.url + '/img/trans.gif', bgneal@442: 'class' : 'mceItemMedia mceItem' + self.getType(data.type).name, bgneal@442: 'data-mce-json' : JSON.serialize(data, "'") bgneal@312: }); bgneal@312: bgneal@442: img.width = data.width || "320"; bgneal@442: img.height = data.height || "240"; bgneal@312: bgneal@442: return img; bgneal@312: }, bgneal@312: bgneal@442: /** bgneal@442: * Converts the JSON data object to a HTML string. bgneal@442: */ bgneal@442: dataToHtml : function(data, force_absolute) { bgneal@442: return this.editor.serializer.serialize(this.dataToImg(data, force_absolute), {force_absolute : force_absolute}); bgneal@442: }, bgneal@312: bgneal@442: /** bgneal@442: * Converts the JSON data object to a HTML string. bgneal@442: */ bgneal@442: htmlToData : function(html) { bgneal@442: var fragment, img, data; bgneal@312: bgneal@442: data = { bgneal@442: type : 'flash', bgneal@442: video: {sources:[]}, bgneal@442: params: {} bgneal@442: }; bgneal@312: bgneal@442: fragment = this.editor.parser.parse(html); bgneal@442: img = fragment.getAll('img')[0]; bgneal@442: bgneal@442: if (img) { bgneal@442: data = JSON.parse(img.attr('data-mce-json')); bgneal@442: data.type = this.getType(img.attr('class')).name.toLowerCase(); bgneal@442: bgneal@442: // Add some extra properties to the data object bgneal@442: tinymce.each(rootAttributes, function(name) { bgneal@442: var value = img.attr(name); bgneal@442: bgneal@442: if (value) bgneal@442: data[name] = value; bgneal@312: }); bgneal@312: } bgneal@312: bgneal@442: return data; bgneal@442: }, bgneal@312: bgneal@442: /** bgneal@442: * Get type item by extension, class, clsid or mime type. bgneal@442: * bgneal@442: * @method getType bgneal@442: * @param {String} value Value to get type item by. bgneal@442: * @return {Object} Type item object or undefined. bgneal@442: */ bgneal@442: getType : function(value) { bgneal@442: var i, values, typeItem; bgneal@442: bgneal@442: // Find type by checking the classes bgneal@442: values = tinymce.explode(value, ' '); bgneal@442: for (i = 0; i < values.length; i++) { bgneal@442: typeItem = this.lookup[values[i]]; bgneal@442: bgneal@442: if (typeItem) bgneal@442: return typeItem; bgneal@442: } bgneal@442: }, bgneal@442: bgneal@442: /** bgneal@442: * Converts a tinymce.html.Node image element to video/object/embed. bgneal@442: */ bgneal@442: imgToObject : function(node, args) { bgneal@442: var self = this, editor = self.editor, video, object, embed, iframe, name, value, data, bgneal@442: source, sources, params, param, typeItem, i, item, mp4Source, replacement, bgneal@442: posterSrc, style; bgneal@442: bgneal@442: // Adds the flash player bgneal@442: function addPlayer(video_src, poster_src) { bgneal@442: var baseUri, flashVars, flashVarsOutput, params, flashPlayer; bgneal@442: bgneal@442: flashPlayer = editor.getParam('flash_video_player_url', self.convertUrl(self.url + '/moxieplayer.swf')); bgneal@442: if (flashPlayer) { bgneal@442: baseUri = editor.documentBaseURI; bgneal@442: data.params.src = flashPlayer; bgneal@442: bgneal@442: // Convert the movie url to absolute urls bgneal@442: if (editor.getParam('flash_video_player_absvideourl', true)) { bgneal@442: video_src = baseUri.toAbsolute(video_src || '', true); bgneal@442: poster_src = baseUri.toAbsolute(poster_src || '', true); bgneal@442: } bgneal@442: bgneal@442: // Generate flash vars bgneal@442: flashVarsOutput = ''; bgneal@442: flashVars = editor.getParam('flash_video_player_flashvars', {url : '$url', poster : '$poster'}); bgneal@442: tinymce.each(flashVars, function(value, name) { bgneal@442: // Replace $url and $poster variables in flashvars value bgneal@442: value = value.replace(/\$url/, video_src || ''); bgneal@442: value = value.replace(/\$poster/, poster_src || ''); bgneal@442: bgneal@442: if (value.length > 0) bgneal@442: flashVarsOutput += (flashVarsOutput ? '&' : '') + name + '=' + escape(value); bgneal@442: }); bgneal@442: bgneal@442: if (flashVarsOutput.length) bgneal@442: data.params.flashvars = flashVarsOutput; bgneal@442: bgneal@442: params = editor.getParam('flash_video_player_params', { bgneal@442: allowfullscreen: true, bgneal@442: allowscriptaccess: true bgneal@442: }); bgneal@442: bgneal@442: tinymce.each(params, function(value, name) { bgneal@442: data.params[name] = "" + value; bgneal@442: }); bgneal@312: } bgneal@442: }; bgneal@442: bgneal@442: data = JSON.parse(node.attr('data-mce-json')); bgneal@442: typeItem = this.getType(node.attr('class')); bgneal@442: bgneal@442: style = node.attr('data-mce-style') bgneal@442: if (!style) { bgneal@442: style = node.attr('style'); bgneal@442: bgneal@442: if (style) bgneal@442: style = editor.dom.serializeStyle(editor.dom.parseStyle(style, 'img')); bgneal@442: } bgneal@442: bgneal@442: // Handle iframe bgneal@442: if (typeItem.name === 'Iframe') { bgneal@442: replacement = new Node('iframe', 1); bgneal@442: bgneal@442: tinymce.each(rootAttributes, function(name) { bgneal@442: var value = node.attr(name); bgneal@442: bgneal@442: if (name == 'class' && value) bgneal@442: value = value.replace(/mceItem.+ ?/g, ''); bgneal@442: bgneal@442: if (value && value.length > 0) bgneal@442: replacement.attr(name, value); bgneal@442: }); bgneal@442: bgneal@442: for (name in data.params) bgneal@442: replacement.attr(name, data.params[name]); bgneal@442: bgneal@442: replacement.attr({ bgneal@442: style: style, bgneal@442: src: data.params.src bgneal@442: }); bgneal@442: bgneal@442: node.replace(replacement); bgneal@442: bgneal@442: return; bgneal@442: } bgneal@442: bgneal@442: // Handle scripts bgneal@442: if (this.editor.settings.media_use_script) { bgneal@442: replacement = new Node('script', 1).attr('type', 'text/javascript'); bgneal@442: bgneal@442: value = new Node('#text', 3); bgneal@442: value.value = 'write' + typeItem.name + '(' + JSON.serialize(tinymce.extend(data.params, { bgneal@442: width: node.attr('width'), bgneal@442: height: node.attr('height') bgneal@442: })) + ');'; bgneal@442: bgneal@442: replacement.append(value); bgneal@442: node.replace(replacement); bgneal@442: bgneal@442: return; bgneal@442: } bgneal@442: bgneal@442: // Add HTML5 video element bgneal@442: if (typeItem.name === 'Video' && data.video.sources[0]) { bgneal@442: // Create new object element bgneal@442: video = new Node('video', 1).attr(tinymce.extend({ bgneal@442: id : node.attr('id'), bgneal@442: width: node.attr('width'), bgneal@442: height: node.attr('height'), bgneal@442: style : style bgneal@442: }, data.video.attrs)); bgneal@442: bgneal@442: // Get poster source and use that for flash fallback bgneal@442: if (data.video.attrs) bgneal@442: posterSrc = data.video.attrs.poster; bgneal@442: bgneal@442: sources = data.video.sources = toArray(data.video.sources); bgneal@442: for (i = 0; i < sources.length; i++) { bgneal@442: if (/\.mp4$/.test(sources[i].src)) bgneal@442: mp4Source = sources[i].src; bgneal@442: } bgneal@442: bgneal@442: if (!sources[0].type) { bgneal@442: video.attr('src', sources[0].src); bgneal@442: sources.splice(0, 1); bgneal@442: } bgneal@442: bgneal@442: for (i = 0; i < sources.length; i++) { bgneal@442: source = new Node('source', 1).attr(sources[i]); bgneal@442: source.shortEnded = true; bgneal@442: video.append(source); bgneal@442: } bgneal@442: bgneal@442: // Create flash fallback for video if we have a mp4 source bgneal@442: if (mp4Source) { bgneal@442: addPlayer(mp4Source, posterSrc); bgneal@442: typeItem = self.getType('flash'); bgneal@442: } else bgneal@442: data.params.src = ''; bgneal@442: } bgneal@442: bgneal@442: // Do we have a params src then we can generate object bgneal@442: if (data.params.src) { bgneal@442: // Is flv movie add player for it bgneal@442: if (/\.flv$/i.test(data.params.src)) bgneal@442: addPlayer(data.params.src, ''); bgneal@442: bgneal@442: if (args && args.force_absolute) bgneal@442: data.params.src = editor.documentBaseURI.toAbsolute(data.params.src); bgneal@442: bgneal@442: // Create new object element bgneal@442: object = new Node('object', 1).attr({ bgneal@442: id : node.attr('id'), bgneal@442: width: node.attr('width'), bgneal@442: height: node.attr('height'), bgneal@442: style : style bgneal@442: }); bgneal@442: bgneal@442: tinymce.each(rootAttributes, function(name) { bgneal@442: if (data[name] && name != 'type') bgneal@442: object.attr(name, data[name]); bgneal@442: }); bgneal@442: bgneal@442: // Add params bgneal@442: for (name in data.params) { bgneal@442: param = new Node('param', 1); bgneal@442: param.shortEnded = true; bgneal@442: value = data.params[name]; bgneal@442: bgneal@442: // Windows media needs to use url instead of src for the media URL bgneal@442: if (name === 'src' && typeItem.name === 'WindowsMedia') bgneal@442: name = 'url'; bgneal@442: bgneal@442: param.attr({name: name, value: value}); bgneal@442: object.append(param); bgneal@442: } bgneal@442: bgneal@442: // Setup add type and classid if strict is disabled bgneal@442: if (this.editor.getParam('media_strict', true)) { bgneal@442: object.attr({ bgneal@442: data: data.params.src, bgneal@442: type: typeItem.mimes[0] bgneal@442: }); bgneal@442: } else { bgneal@442: object.attr({ bgneal@442: classid: "clsid:" + typeItem.clsids[0], bgneal@442: codebase: typeItem.codebase bgneal@442: }); bgneal@442: bgneal@442: embed = new Node('embed', 1); bgneal@442: embed.shortEnded = true; bgneal@442: embed.attr({ bgneal@442: id: node.attr('id'), bgneal@442: width: node.attr('width'), bgneal@442: height: node.attr('height'), bgneal@442: style : style, bgneal@442: type: typeItem.mimes[0] bgneal@442: }); bgneal@442: bgneal@442: for (name in data.params) bgneal@442: embed.attr(name, data.params[name]); bgneal@442: bgneal@442: tinymce.each(rootAttributes, function(name) { bgneal@442: if (data[name] && name != 'type') bgneal@442: embed.attr(name, data[name]); bgneal@442: }); bgneal@442: bgneal@442: object.append(embed); bgneal@442: } bgneal@442: bgneal@442: // Insert raw HTML bgneal@442: if (data.object_html) { bgneal@442: value = new Node('#text', 3); bgneal@442: value.raw = true; bgneal@442: value.value = data.object_html; bgneal@442: object.append(value); bgneal@442: } bgneal@442: bgneal@442: // Append object to video element if it exists bgneal@442: if (video) bgneal@442: video.append(object); bgneal@442: } bgneal@442: bgneal@442: if (video) { bgneal@442: // Insert raw HTML bgneal@442: if (data.video_html) { bgneal@442: value = new Node('#text', 3); bgneal@442: value.raw = true; bgneal@442: value.value = data.video_html; bgneal@442: video.append(value); bgneal@442: } bgneal@442: } bgneal@442: bgneal@442: if (video || object) bgneal@442: node.replace(video || object); bgneal@442: else bgneal@442: node.remove(); bgneal@442: }, bgneal@442: bgneal@442: /** bgneal@442: * Converts a tinymce.html.Node video/object/embed to an img element. bgneal@442: * bgneal@442: * The video/object/embed will be converted into an image placeholder with a JSON data attribute like this: bgneal@442: * bgneal@442: * bgneal@442: * The JSON structure will be like this: bgneal@442: * {'params':{'flashvars':'something','quality':'high','src':'someurl'}, 'video':{'sources':[{src: 'someurl', type: 'video/mp4'}]}} bgneal@442: */ bgneal@442: objectToImg : function(node) { bgneal@442: var object, embed, video, iframe, img, name, id, width, height, style, i, html, bgneal@442: param, params, source, sources, data, type, lookup = this.lookup, bgneal@442: matches, attrs, urlConverter = this.editor.settings.url_converter, bgneal@442: urlConverterScope = this.editor.settings.url_converter_scope; bgneal@442: bgneal@442: function getInnerHTML(node) { bgneal@442: return new tinymce.html.Serializer({ bgneal@442: inner: true, bgneal@442: validate: false bgneal@442: }).serialize(node); bgneal@442: }; bgneal@442: bgneal@442: // If node isn't in document bgneal@442: if (!node.parent) bgneal@442: return; bgneal@442: bgneal@442: // Handle media scripts bgneal@442: if (node.name === 'script') { bgneal@442: if (node.firstChild) bgneal@442: matches = scriptRegExp.exec(node.firstChild.value); bgneal@442: bgneal@442: if (!matches) bgneal@442: return; bgneal@442: bgneal@442: type = matches[1]; bgneal@442: data = {video : {}, params : JSON.parse(matches[2])}; bgneal@442: width = data.params.width; bgneal@442: height = data.params.height; bgneal@442: } bgneal@442: bgneal@442: // Setup data objects bgneal@442: data = data || { bgneal@442: video : {}, bgneal@442: params : {} bgneal@442: }; bgneal@442: bgneal@442: // Setup new image object bgneal@442: img = new Node('img', 1); bgneal@442: img.attr({ bgneal@442: src : this.editor.theme.url + '/img/trans.gif' bgneal@312: }); bgneal@312: bgneal@442: // Video element bgneal@442: name = node.name; bgneal@442: if (name === 'video') { bgneal@442: video = node; bgneal@442: object = node.getAll('object')[0]; bgneal@442: embed = node.getAll('embed')[0]; bgneal@442: width = video.attr('width'); bgneal@442: height = video.attr('height'); bgneal@442: id = video.attr('id'); bgneal@442: data.video = {attrs : {}, sources : []}; bgneal@312: bgneal@442: // Get all video attributes bgneal@442: attrs = data.video.attrs; bgneal@442: for (name in video.attributes.map) bgneal@442: attrs[name] = video.attributes.map[name]; bgneal@312: bgneal@442: source = node.attr('src'); bgneal@442: if (source) bgneal@442: data.video.sources.push({src : urlConverter.call(urlConverterScope, source, 'src', 'video')}); bgneal@312: bgneal@442: // Get all sources bgneal@442: sources = video.getAll("source"); bgneal@442: for (i = 0; i < sources.length; i++) { bgneal@442: source = sources[i].remove(); bgneal@312: bgneal@442: data.video.sources.push({ bgneal@442: src: urlConverter.call(urlConverterScope, source.attr('src'), 'src', 'source'), bgneal@442: type: source.attr('type'), bgneal@442: media: source.attr('media') bgneal@442: }); bgneal@312: } bgneal@312: bgneal@442: // Convert the poster URL bgneal@442: if (attrs.poster) bgneal@442: attrs.poster = urlConverter.call(urlConverterScope, attrs.poster, 'poster', 'video'); bgneal@442: } bgneal@312: bgneal@442: // Object element bgneal@442: if (node.name === 'object') { bgneal@442: object = node; bgneal@442: embed = node.getAll('embed')[0]; bgneal@442: } bgneal@312: bgneal@442: // Embed element bgneal@442: if (node.name === 'embed') bgneal@442: embed = node; bgneal@312: bgneal@442: // Iframe element bgneal@442: if (node.name === 'iframe') { bgneal@442: iframe = node; bgneal@442: type = 'Iframe'; bgneal@442: } bgneal@312: bgneal@442: if (object) { bgneal@442: // Get width/height bgneal@442: width = width || object.attr('width'); bgneal@442: height = height || object.attr('height'); bgneal@442: style = style || object.attr('style'); bgneal@442: id = id || object.attr('id'); bgneal@312: bgneal@442: // Get all object params bgneal@442: params = object.getAll("param"); bgneal@442: for (i = 0; i < params.length; i++) { bgneal@442: param = params[i]; bgneal@442: name = param.remove().attr('name'); bgneal@312: bgneal@442: if (!excludedAttrs[name]) bgneal@442: data.params[name] = param.attr('value'); bgneal@442: } bgneal@312: bgneal@442: data.params.src = data.params.src || object.attr('data'); bgneal@442: } bgneal@312: bgneal@442: if (embed) { bgneal@442: // Get width/height bgneal@442: width = width || embed.attr('width'); bgneal@442: height = height || embed.attr('height'); bgneal@442: style = style || embed.attr('style'); bgneal@442: id = id || embed.attr('id'); bgneal@312: bgneal@442: // Get all embed attributes bgneal@442: for (name in embed.attributes.map) { bgneal@442: if (!excludedAttrs[name] && !data.params[name]) bgneal@442: data.params[name] = embed.attributes.map[name]; bgneal@442: } bgneal@442: } bgneal@312: bgneal@442: if (iframe) { bgneal@442: // Get width/height bgneal@442: width = iframe.attr('width'); bgneal@442: height = iframe.attr('height'); bgneal@442: style = style || iframe.attr('style'); bgneal@442: id = iframe.attr('id'); bgneal@312: bgneal@442: tinymce.each(rootAttributes, function(name) { bgneal@442: img.attr(name, iframe.attr(name)); bgneal@442: }); bgneal@442: bgneal@442: // Get all iframe attributes bgneal@442: for (name in iframe.attributes.map) { bgneal@442: if (!excludedAttrs[name] && !data.params[name]) bgneal@442: data.params[name] = iframe.attributes.map[name]; bgneal@442: } bgneal@442: } bgneal@312: bgneal@312: // Use src not movie bgneal@442: if (data.params.movie) { bgneal@442: data.params.src = data.params.src || data.params.movie; bgneal@442: delete data.params.movie; bgneal@312: } bgneal@312: bgneal@442: // Convert the URL to relative/absolute depending on configuration bgneal@442: if (data.params.src) bgneal@442: data.params.src = urlConverter.call(urlConverterScope, data.params.src, 'src', 'object'); bgneal@442: bgneal@442: if (video) bgneal@442: type = lookup.video.name; bgneal@442: bgneal@442: if (object && !type) bgneal@442: type = (lookup[(object.attr('clsid') || '').toLowerCase()] || lookup[(object.attr('type') || '').toLowerCase()] || {}).name; bgneal@442: bgneal@442: if (embed && !type) bgneal@442: type = (lookup[(embed.attr('type') || '').toLowerCase()] || {}).name; bgneal@442: bgneal@442: // Replace the video/object/embed element with a placeholder image containing the data bgneal@442: node.replace(img); bgneal@442: bgneal@442: // Remove embed bgneal@442: if (embed) bgneal@442: embed.remove(); bgneal@442: bgneal@442: // Serialize the inner HTML of the object element bgneal@442: if (object) { bgneal@442: html = getInnerHTML(object.remove()); bgneal@442: bgneal@442: if (html) bgneal@442: data.object_html = html; bgneal@312: } bgneal@312: bgneal@442: // Serialize the inner HTML of the video element bgneal@442: if (video) { bgneal@442: html = getInnerHTML(video.remove()); bgneal@312: bgneal@442: if (html) bgneal@442: data.video_html = html; bgneal@312: } bgneal@312: bgneal@442: // Set width/height of placeholder bgneal@442: img.attr({ bgneal@442: id : id, bgneal@442: 'class' : 'mceItemMedia mceItem' + (type || 'Flash'), bgneal@442: style : style, bgneal@442: width : width || "320", bgneal@442: height : height || "240", bgneal@442: "data-mce-json" : JSON.serialize(data, "'") bgneal@442: }); bgneal@312: } bgneal@312: }); bgneal@312: bgneal@312: // Register plugin bgneal@312: tinymce.PluginManager.add('media', tinymce.plugins.MediaPlugin); bgneal@312: })();