4 * Copyright 2009, Moxiecode Systems AB
5 * Released under LGPL License.
7 * License: http://tinymce.moxiecode.com/license
8 * Contributing: http://tinymce.moxiecode.com/contributing
12 var rootAttributes
= tinymce
.explode('id,name,width,height,style,align,class,hspace,vspace,bgcolor,type'), excludedAttrs
= tinymce
.makeMap(rootAttributes
.join(',')), Node
= tinymce
.html
.Node
,
13 mediaTypes
, scriptRegExp
, JSON
= tinymce
.util
.JSON
, mimeTypes
;
15 // Media types supported by this plugin
17 // Type, clsid:s, mime types, codebase
18 ["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"],
19 ["ShockWave", "166b1bca-3f9c-11cf-8075-444553540000", "application/x-director", "http://download.macromedia.com/pub/shockwave/cabs/director/sw.cab#version=8,5,1,0"],
20 ["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"],
21 ["QuickTime", "02bf25d5-8c17-4b23-bc80-d3488abddc6b", "video/quicktime", "http://www.apple.com/qtactivex/qtplugin.cab#version=6,0,2,0"],
22 ["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"],
23 ["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"],
24 ["Silverlight", "dfeaf541-f3e1-4c24-acac-99c30715084a", "application/x-silverlight-2"],
31 function toArray(obj
) {
34 if (obj
&& !obj
.splice
) {
37 for (i
= 0; true; i
++) {
50 tinymce
.create('tinymce.plugins.MediaPlugin', {
51 init : function(ed
, url
) {
52 var self
= this, lookup
= {}, i
, y
, item
, name
;
54 function isMediaImg(node
) {
55 return node
&& node
.nodeName
=== 'IMG' && ed
.dom
.hasClass(node
, 'mceItemMedia');
61 // Parse media types into a lookup table
63 for (i
= 0; i
< mediaTypes
.length
; i
++) {
64 name
= mediaTypes
[i
][0];
68 clsids
: tinymce
.explode(mediaTypes
[i
][1] || ''),
69 mimes
: tinymce
.explode(mediaTypes
[i
][2] || ''),
70 codebase
: mediaTypes
[i
][3]
73 for (y
= 0; y
< item
.clsids
.length
; y
++)
74 lookup
['clsid:' + item
.clsids
[y
]] = item
;
76 for (y
= 0; y
< item
.mimes
.length
; y
++)
77 lookup
[item
.mimes
[y
]] = item
;
79 lookup
['mceItem' + name
] = item
;
80 lookup
[name
.toLowerCase()] = item
;
82 scriptRegExp
+= (scriptRegExp
? '|' : '') + name
;
85 // Handle the media_types setting
86 tinymce
.each(ed
.getParam("media_types",
87 "video=mp4,m4v,ogv,webm;" +
91 "quicktime=mov,qt,mpg,mpeg;" +
93 "windowsmedia=avi,wmv,wm,asf,asx,wmx,wvx;" +
94 "realmedia=rm,ra,ram;" +
97 ).split(';'), function(item
) {
98 var i
, extensions
, type
;
100 item
= item
.split(/=/);
101 extensions
= tinymce
.explode(item
[1].toLowerCase());
102 for (i
= 0; i
< extensions
.length
; i
++) {
103 type
= lookup
[item
[0].toLowerCase()];
106 lookup
[extensions
[i
]] = type
;
110 scriptRegExp
= new RegExp('write(' + scriptRegExp
+ ')\\(([^)]+)\\)');
111 self
.lookup
= lookup
;
113 ed
.onPreInit
.add(function() {
114 // Allow video elements
115 ed
.schema
.addValidElements('object[id|style|width|height|classid|codebase|*],param[name|value],embed[id|style|width|height|type|src|*],video[*],audio[*],source[*]');
117 // Convert video elements to image placeholder
118 ed
.parser
.addNodeFilter('object,embed,video,audio,script,iframe', function(nodes
) {
119 var i
= nodes
.length
;
122 self
.objectToImg(nodes
[i
]);
125 // Convert image placeholders to video elements
126 ed
.serializer
.addNodeFilter('img', function(nodes
, name
, args
) {
127 var i
= nodes
.length
, node
;
131 if ((node
.attr('class') || '').indexOf('mceItemMedia') !== -1)
132 self
.imgToObject(node
, args
);
137 ed
.onInit
.add(function() {
138 // Display "media" instead of "img" in element path
139 if (ed
.theme
&& ed
.theme
.onResolveName
) {
140 ed
.theme
.onResolveName
.add(function(theme
, path_object
) {
141 if (path_object
.name
=== 'img' && ed
.dom
.hasClass(path_object
.node
, 'mceItemMedia'))
142 path_object
.name
= 'media';
146 // Add contect menu if it's loaded
147 if (ed
&& ed
.plugins
.contextmenu
) {
148 ed
.plugins
.contextmenu
.onContextMenu
.add(function(plugin
, menu
, element
) {
149 if (element
.nodeName
=== 'IMG' && element
.className
.indexOf('mceItemMedia') !== -1)
150 menu
.add({title
: 'media.edit', icon
: 'media', cmd
: 'mceMedia'});
156 ed
.addCommand('mceMedia', function() {
159 img
= ed
.selection
.getNode();
160 if (isMediaImg(img
)) {
161 data
= ed
.dom
.getAttrib(img
, 'data-mce-json');
163 data
= JSON
.parse(data
);
165 // Add some extra properties to the data object
166 tinymce
.each(rootAttributes
, function(name
) {
167 var value
= ed
.dom
.getAttrib(img
, name
);
173 data
.type
= self
.getType(img
.className
).name
.toLowerCase();
185 ed
.windowManager
.open({
186 file
: url
+ '/media.htm',
187 width
: 430 + parseInt(ed
.getLang('media.delta_width', 0)),
188 height
: 500 + parseInt(ed
.getLang('media.delta_height', 0)),
197 ed
.addButton('media', {title
: 'media.desc', cmd
: 'mceMedia'});
199 // Update media selection status
200 ed
.onNodeChange
.add(function(ed
, cm
, node
) {
201 cm
.setActive('media', isMediaImg(node
));
205 convertUrl : function(url
, force_absolute
) {
206 var self
= this, editor
= self
.editor
, settings
= editor
.settings
,
207 urlConverter
= settings
.url_converter
,
208 urlConverterScope
= settings
.url_converter_scope
|| self
;
214 return editor
.documentBaseURI
.toAbsolute(url
);
216 return urlConverter
.call(urlConverterScope
, url
, 'src', 'object');
219 getInfo : function() {
222 author
: 'Moxiecode Systems AB',
223 authorurl
: 'http://tinymce.moxiecode.com',
224 infourl
: 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/media',
225 version
: tinymce
.majorVersion
+ "." + tinymce
.minorVersion
230 * Converts the JSON data object to an img node.
232 dataToImg : function(data
, force_absolute
) {
233 var self
= this, editor
= self
.editor
, baseUri
= editor
.documentBaseURI
, sources
, attrs
, img
, i
;
235 data
.params
.src
= self
.convertUrl(data
.params
.src
, force_absolute
);
237 attrs
= data
.video
.attrs
;
239 attrs
.src
= self
.convertUrl(attrs
.src
, force_absolute
);
242 attrs
.poster
= self
.convertUrl(attrs
.poster
, force_absolute
);
244 sources
= toArray(data
.video
.sources
);
246 for (i
= 0; i
< sources
.length
; i
++)
247 sources
[i
].src
= self
.convertUrl(sources
[i
].src
, force_absolute
);
250 img
= self
.editor
.dom
.create('img', {
254 hspace
: data
.hspace
,
255 vspace
: data
.vspace
,
256 src
: self
.editor
.theme
.url
+ '/img/trans.gif',
257 'class' : 'mceItemMedia mceItem' + self
.getType(data
.type
).name
,
258 'data-mce-json' : JSON
.serialize(data
, "'")
261 img
.width
= data
.width
|| (data
.type
== 'audio' ? "300" : "320");
262 img
.height
= data
.height
|| (data
.type
== 'audio' ? "32" : "240");
268 * Converts the JSON data object to a HTML string.
270 dataToHtml : function(data
, force_absolute
) {
271 return this.editor
.serializer
.serialize(this.dataToImg(data
, force_absolute
), {forced_root_block
: '', force_absolute
: force_absolute
});
275 * Converts the JSON data object to a HTML string.
277 htmlToData : function(html
) {
278 var fragment
, img
, data
;
286 fragment
= this.editor
.parser
.parse(html
);
287 img
= fragment
.getAll('img')[0];
290 data
= JSON
.parse(img
.attr('data-mce-json'));
291 data
.type
= this.getType(img
.attr('class')).name
.toLowerCase();
293 // Add some extra properties to the data object
294 tinymce
.each(rootAttributes
, function(name
) {
295 var value
= img
.attr(name
);
306 * Get type item by extension, class, clsid or mime type.
309 * @param {String} value Value to get type item by.
310 * @return {Object} Type item object or undefined.
312 getType : function(value
) {
313 var i
, values
, typeItem
;
315 // Find type by checking the classes
316 values
= tinymce
.explode(value
, ' ');
317 for (i
= 0; i
< values
.length
; i
++) {
318 typeItem
= this.lookup
[values
[i
]];
326 * Converts a tinymce.html.Node image element to video/object/embed.
328 imgToObject : function(node
, args
) {
329 var self
= this, editor
= self
.editor
, video
, object
, embed
, iframe
, name
, value
, data
,
330 source
, sources
, params
, param
, typeItem
, i
, item
, mp4Source
, replacement
,
331 posterSrc
, style
, audio
;
333 // Adds the flash player
334 function addPlayer(video_src
, poster_src
) {
335 var baseUri
, flashVars
, flashVarsOutput
, params
, flashPlayer
;
337 flashPlayer
= editor
.getParam('flash_video_player_url', self
.convertUrl(self
.url
+ '/moxieplayer.swf'));
339 baseUri
= editor
.documentBaseURI
;
340 data
.params
.src
= flashPlayer
;
342 // Convert the movie url to absolute urls
343 if (editor
.getParam('flash_video_player_absvideourl', true)) {
344 video_src
= baseUri
.toAbsolute(video_src
|| '', true);
345 poster_src
= baseUri
.toAbsolute(poster_src
|| '', true);
348 // Generate flash vars
349 flashVarsOutput
= '';
350 flashVars
= editor
.getParam('flash_video_player_flashvars', {url
: '$url', poster
: '$poster'});
351 tinymce
.each(flashVars
, function(value
, name
) {
352 // Replace $url and $poster variables in flashvars value
353 value
= value
.replace(/\$url/, video_src
|| '');
354 value
= value
.replace(/\$poster/, poster_src
|| '');
356 if (value
.length
> 0)
357 flashVarsOutput
+= (flashVarsOutput
? '&' : '') + name
+ '=' + escape(value
);
360 if (flashVarsOutput
.length
)
361 data
.params
.flashvars
= flashVarsOutput
;
363 params
= editor
.getParam('flash_video_player_params', {
364 allowfullscreen
: true,
365 allowscriptaccess
: true
368 tinymce
.each(params
, function(value
, name
) {
369 data
.params
[name
] = "" + value
;
374 data
= node
.attr('data-mce-json');
378 data
= JSON
.parse(data
);
379 typeItem
= this.getType(node
.attr('class'));
381 style
= node
.attr('data-mce-style')
383 style
= node
.attr('style');
386 style
= editor
.dom
.serializeStyle(editor
.dom
.parseStyle(style
, 'img'));
390 if (typeItem
.name
=== 'Iframe') {
391 replacement
= new Node('iframe', 1);
393 tinymce
.each(rootAttributes
, function(name
) {
394 var value
= node
.attr(name
);
396 if (name
== 'class' && value
)
397 value
= value
.replace(/mceItem.+ ?/g, '');
399 if (value
&& value
.length
> 0)
400 replacement
.attr(name
, value
);
403 for (name
in data
.params
)
404 replacement
.attr(name
, data
.params
[name
]);
411 node
.replace(replacement
);
417 if (this.editor
.settings
.media_use_script
) {
418 replacement
= new Node('script', 1).attr('type', 'text/javascript');
420 value
= new Node('#text', 3);
421 value
.value
= 'write' + typeItem
.name
+ '(' + JSON
.serialize(tinymce
.extend(data
.params
, {
422 width
: node
.attr('width'),
423 height
: node
.attr('height')
426 replacement
.append(value
);
427 node
.replace(replacement
);
432 // Add HTML5 video element
433 if (typeItem
.name
=== 'Video' && data
.video
.sources
[0]) {
434 // Create new object element
435 video
= new Node('video', 1).attr(tinymce
.extend({
436 id
: node
.attr('id'),
437 width
: node
.attr('width'),
438 height
: node
.attr('height'),
440 }, data
.video
.attrs
));
442 // Get poster source and use that for flash fallback
443 if (data
.video
.attrs
)
444 posterSrc
= data
.video
.attrs
.poster
;
446 sources
= data
.video
.sources
= toArray(data
.video
.sources
);
447 for (i
= 0; i
< sources
.length
; i
++) {
448 if (/\.mp4$/.test(sources
[i
].src
))
449 mp4Source
= sources
[i
].src
;
452 if (!sources
[0].type
) {
453 video
.attr('src', sources
[0].src
);
454 sources
.splice(0, 1);
457 for (i
= 0; i
< sources
.length
; i
++) {
458 source
= new Node('source', 1).attr(sources
[i
]);
459 source
.shortEnded
= true;
460 video
.append(source
);
463 // Create flash fallback for video if we have a mp4 source
465 addPlayer(mp4Source
, posterSrc
);
466 typeItem
= self
.getType('flash');
468 data
.params
.src
= '';
471 // Add HTML5 audio element
472 if (typeItem
.name
=== 'Audio' && data
.video
.sources
[0]) {
473 // Create new object element
474 audio
= new Node('audio', 1).attr(tinymce
.extend({
475 id
: node
.attr('id'),
476 width
: node
.attr('width'),
477 height
: node
.attr('height'),
479 }, data
.video
.attrs
));
481 // Get poster source and use that for flash fallback
482 if (data
.video
.attrs
)
483 posterSrc
= data
.video
.attrs
.poster
;
485 sources
= data
.video
.sources
= toArray(data
.video
.sources
);
486 if (!sources
[0].type
) {
487 audio
.attr('src', sources
[0].src
);
488 sources
.splice(0, 1);
491 for (i
= 0; i
< sources
.length
; i
++) {
492 source
= new Node('source', 1).attr(sources
[i
]);
493 source
.shortEnded
= true;
494 audio
.append(source
);
497 data
.params
.src
= '';
500 if (typeItem
.name
=== 'EmbeddedAudio') {
501 embed
= new Node('embed', 1);
502 embed
.shortEnded
= true;
505 width
: node
.attr('width'),
506 height
: node
.attr('height'),
508 type
: node
.attr('type')
511 for (name
in data
.params
)
512 embed
.attr(name
, data
.params
[name
]);
514 tinymce
.each(rootAttributes
, function(name
) {
515 if (data
[name
] && name
!= 'type')
516 embed
.attr(name
, data
[name
]);
519 data
.params
.src
= '';
522 // Do we have a params src then we can generate object
523 if (data
.params
.src
) {
524 // Is flv movie add player for it
525 if (/\.flv$/i.test(data
.params
.src
))
526 addPlayer(data
.params
.src
, '');
528 if (args
&& args
.force_absolute
)
529 data
.params
.src
= editor
.documentBaseURI
.toAbsolute(data
.params
.src
);
531 // Create new object element
532 object
= new Node('object', 1).attr({
533 id
: node
.attr('id'),
534 width
: node
.attr('width'),
535 height
: node
.attr('height'),
539 tinymce
.each(rootAttributes
, function(name
) {
540 var value
= data
[name
];
542 if (name
== 'class' && value
)
543 value
= value
.replace(/mceItem.+ ?/g, '');
545 if (value
&& name
!= 'type')
546 object
.attr(name
, value
);
550 for (name
in data
.params
) {
551 param
= new Node('param', 1);
552 param
.shortEnded
= true;
553 value
= data
.params
[name
];
555 // Windows media needs to use url instead of src for the media URL
556 if (name
=== 'src' && typeItem
.name
=== 'WindowsMedia')
559 param
.attr({name
: name
, value
: value
});
560 object
.append(param
);
563 // Setup add type and classid if strict is disabled
564 if (this.editor
.getParam('media_strict', true)) {
566 data
: data
.params
.src
,
567 type
: typeItem
.mimes
[0]
571 classid
: "clsid:" + typeItem
.clsids
[0],
572 codebase
: typeItem
.codebase
575 embed
= new Node('embed', 1);
576 embed
.shortEnded
= true;
579 width
: node
.attr('width'),
580 height
: node
.attr('height'),
582 type
: typeItem
.mimes
[0]
585 for (name
in data
.params
)
586 embed
.attr(name
, data
.params
[name
]);
588 tinymce
.each(rootAttributes
, function(name
) {
589 if (data
[name
] && name
!= 'type')
590 embed
.attr(name
, data
[name
]);
593 object
.append(embed
);
597 if (data
.object_html
) {
598 value
= new Node('#text', 3);
600 value
.value
= data
.object_html
;
601 object
.append(value
);
604 // Append object to video element if it exists
606 video
.append(object
);
611 if (data
.video_html
) {
612 value
= new Node('#text', 3);
614 value
.value
= data
.video_html
;
621 if (data
.video_html
) {
622 value
= new Node('#text', 3);
624 value
.value
= data
.video_html
;
629 var n
= video
|| audio
|| object
|| embed
;
637 * Converts a tinymce.html.Node video/object/embed to an img element.
639 * The video/object/embed will be converted into an image placeholder with a JSON data attribute like this:
640 * <img class="mceItemMedia mceItemFlash" width="100" height="100" data-mce-json="{..}" />
642 * The JSON structure will be like this:
643 * {'params':{'flashvars':'something','quality':'high','src':'someurl'}, 'video':{'sources':[{src: 'someurl', type: 'video/mp4'}]}}
645 objectToImg : function(node
) {
646 var object
, embed
, video
, iframe
, img
, name
, id
, width
, height
, style
, i
, html
,
647 param
, params
, source
, sources
, data
, type
, lookup
= this.lookup
,
648 matches
, attrs
, urlConverter
= this.editor
.settings
.url_converter
,
649 urlConverterScope
= this.editor
.settings
.url_converter_scope
,
650 hspace
, vspace
, align
, bgcolor
;
652 function getInnerHTML(node
) {
653 return new tinymce
.html
.Serializer({
659 function lookupAttribute(o
, attr
) {
660 return lookup
[(o
.attr(attr
) || '').toLowerCase()];
663 function lookupExtension(src
) {
664 var ext
= src
.replace(/^.*\.([^.]+)$/, '$1');
665 return lookup
[ext
.toLowerCase() || ''];
668 // If node isn't in document
672 // Handle media scripts
673 if (node
.name
=== 'script') {
675 matches
= scriptRegExp
.exec(node
.firstChild
.value
);
681 data
= {video
: {}, params
: JSON
.parse(matches
[2])};
682 width
= data
.params
.width
;
683 height
= data
.params
.height
;
686 // Setup data objects
692 // Setup new image object
693 img
= new Node('img', 1);
695 src
: this.editor
.theme
.url
+ '/img/trans.gif'
700 if (name
=== 'video' || name
== 'audio') {
702 object
= node
.getAll('object')[0];
703 embed
= node
.getAll('embed')[0];
704 width
= video
.attr('width');
705 height
= video
.attr('height');
706 id
= video
.attr('id');
707 data
.video
= {attrs
: {}, sources
: []};
709 // Get all video attributes
710 attrs
= data
.video
.attrs
;
711 for (name
in video
.attributes
.map
)
712 attrs
[name
] = video
.attributes
.map
[name
];
714 source
= node
.attr('src');
716 data
.video
.sources
.push({src
: urlConverter
.call(urlConverterScope
, source
, 'src', node
.name
)});
719 sources
= video
.getAll("source");
720 for (i
= 0; i
< sources
.length
; i
++) {
721 source
= sources
[i
].remove();
723 data
.video
.sources
.push({
724 src
: urlConverter
.call(urlConverterScope
, source
.attr('src'), 'src', 'source'),
725 type
: source
.attr('type'),
726 media
: source
.attr('media')
730 // Convert the poster URL
732 attrs
.poster
= urlConverter
.call(urlConverterScope
, attrs
.poster
, 'poster', node
.name
);
736 if (node
.name
=== 'object') {
738 embed
= node
.getAll('embed')[0];
742 if (node
.name
=== 'embed')
746 if (node
.name
=== 'iframe') {
753 width
= width
|| object
.attr('width');
754 height
= height
|| object
.attr('height');
755 style
= style
|| object
.attr('style');
756 id
= id
|| object
.attr('id');
757 hspace
= hspace
|| object
.attr('hspace');
758 vspace
= vspace
|| object
.attr('vspace');
759 align
= align
|| object
.attr('align');
760 bgcolor
= bgcolor
|| object
.attr('bgcolor');
761 data
.name
= object
.attr('name');
763 // Get all object params
764 params
= object
.getAll("param");
765 for (i
= 0; i
< params
.length
; i
++) {
767 name
= param
.remove().attr('name');
769 if (!excludedAttrs
[name
])
770 data
.params
[name
] = param
.attr('value');
773 data
.params
.src
= data
.params
.src
|| object
.attr('data');
778 width
= width
|| embed
.attr('width');
779 height
= height
|| embed
.attr('height');
780 style
= style
|| embed
.attr('style');
781 id
= id
|| embed
.attr('id');
782 hspace
= hspace
|| embed
.attr('hspace');
783 vspace
= vspace
|| embed
.attr('vspace');
784 align
= align
|| embed
.attr('align');
785 bgcolor
= bgcolor
|| embed
.attr('bgcolor');
787 // Get all embed attributes
788 for (name
in embed
.attributes
.map
) {
789 if (!excludedAttrs
[name
] && !data
.params
[name
])
790 data
.params
[name
] = embed
.attributes
.map
[name
];
796 width
= iframe
.attr('width');
797 height
= iframe
.attr('height');
798 style
= style
|| iframe
.attr('style');
799 id
= iframe
.attr('id');
800 hspace
= iframe
.attr('hspace');
801 vspace
= iframe
.attr('vspace');
802 align
= iframe
.attr('align');
803 bgcolor
= iframe
.attr('bgcolor');
805 tinymce
.each(rootAttributes
, function(name
) {
806 img
.attr(name
, iframe
.attr(name
));
809 // Get all iframe attributes
810 for (name
in iframe
.attributes
.map
) {
811 if (!excludedAttrs
[name
] && !data
.params
[name
])
812 data
.params
[name
] = iframe
.attributes
.map
[name
];
817 if (data
.params
.movie
) {
818 data
.params
.src
= data
.params
.src
|| data
.params
.movie
;
819 delete data
.params
.movie
;
822 // Convert the URL to relative/absolute depending on configuration
824 data
.params
.src
= urlConverter
.call(urlConverterScope
, data
.params
.src
, 'src', 'object');
827 if (node
.name
=== 'video')
828 type
= lookup
.video
.name
;
829 else if (node
.name
=== 'audio')
830 type
= lookup
.audio
.name
;
834 type
= (lookupAttribute(object
, 'clsid') || lookupAttribute(object
, 'classid') || lookupAttribute(object
, 'type') || {}).name
;
837 type
= (lookupAttribute(embed
, 'type') || lookupExtension(data
.params
.src
) || {}).name
;
839 // for embedded audio we preserve the original specified type
840 if (embed
&& type
== 'EmbeddedAudio') {
841 data
.params
.type
= embed
.attr('type');
844 // Replace the video/object/embed element with a placeholder image containing the data
851 // Serialize the inner HTML of the object element
853 html
= getInnerHTML(object
.remove());
856 data
.object_html
= html
;
859 // Serialize the inner HTML of the video element
861 html
= getInnerHTML(video
.remove());
864 data
.video_html
= html
;
867 data
.hspace
= hspace
;
868 data
.vspace
= vspace
;
870 data
.bgcolor
= bgcolor
;
872 // Set width/height of placeholder
875 'class' : 'mceItemMedia mceItem' + (type
|| 'Flash'),
877 width
: width
|| (node
.name
== 'audio' ? "300" : "320"),
878 height
: height
|| (node
.name
== 'audio' ? "32" : "240"),
883 "data-mce-json" : JSON
.serialize(data
, "'")
889 tinymce
.PluginManager
.add('media', tinymce
.plugins
.MediaPlugin
);