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