src/pyams_skin/resources/js/ext/tinymce/dev/plugins/media/plugin.js
changeset 557 bca7a7e058a3
equal deleted inserted replaced
-1:000000000000 557:bca7a7e058a3
       
     1 /**
       
     2  * plugin.js
       
     3  *
       
     4  * Copyright, Moxiecode Systems AB
       
     5  * Released under LGPL License.
       
     6  *
       
     7  * License: http://www.tinymce.com/license
       
     8  * Contributing: http://www.tinymce.com/contributing
       
     9  */
       
    10 
       
    11 /*jshint maxlen:255 */
       
    12 /*eslint max-len:0 */
       
    13 /*global tinymce:true */
       
    14 
       
    15 tinymce.PluginManager.add('media', function(editor, url) {
       
    16 	var urlPatterns = [
       
    17 		{regex: /youtu\.be\/([\w\-.]+)/, type: 'iframe', w: 425, h: 350, url: '//www.youtube.com/embed/$1'},
       
    18 		{regex: /youtube\.com(.+)v=([^&]+)/, type: 'iframe', w: 425, h: 350, url: '//www.youtube.com/embed/$2'},
       
    19 		{regex: /vimeo\.com\/([0-9]+)/, type: 'iframe', w: 425, h: 350, url: '//player.vimeo.com/video/$1?title=0&byline=0&portrait=0&color=8dc7dc'},
       
    20 		{regex: /vimeo\.com\/(.*)\/([0-9]+)/, type: "iframe", w: 425, h: 350, url: "//player.vimeo.com/video/$2?title=0&byline=0"},
       
    21 		{regex: /maps\.google\.([a-z]{2,3})\/maps\/(.+)msid=(.+)/, type: 'iframe', w: 425, h: 350, url: '//maps.google.com/maps/ms?msid=$2&output=embed"'}
       
    22 	];
       
    23 
       
    24 	var embedChange = (tinymce.Env.ie && tinymce.Env.ie <= 8) ? 'onChange' : 'onInput';
       
    25 
       
    26 	function guessMime(url) {
       
    27 		url = url.toLowerCase();
       
    28 
       
    29 		if (url.indexOf('.mp3') != -1) {
       
    30 			return 'audio/mpeg';
       
    31 		}
       
    32 
       
    33 		if (url.indexOf('.wav') != -1) {
       
    34 			return 'audio/wav';
       
    35 		}
       
    36 
       
    37 		if (url.indexOf('.mp4') != -1) {
       
    38 			return 'video/mp4';
       
    39 		}
       
    40 
       
    41 		if (url.indexOf('.webm') != -1) {
       
    42 			return 'video/webm';
       
    43 		}
       
    44 
       
    45 		if (url.indexOf('.ogg') != -1) {
       
    46 			return 'video/ogg';
       
    47 		}
       
    48 
       
    49 		if (url.indexOf('.swf') != -1) {
       
    50 			return 'application/x-shockwave-flash';
       
    51 		}
       
    52 
       
    53 		return '';
       
    54 	}
       
    55 
       
    56 	function getVideoScriptMatch(src) {
       
    57 		var prefixes = editor.settings.media_scripts;
       
    58 
       
    59 		if (prefixes) {
       
    60 			for (var i = 0; i < prefixes.length; i++) {
       
    61 				if (src.indexOf(prefixes[i].filter) !== -1) {
       
    62 					return prefixes[i];
       
    63 				}
       
    64 			}
       
    65 		}
       
    66 	}
       
    67 
       
    68 	function showDialog() {
       
    69 		var win, width, height, data;
       
    70 
       
    71 		var generalFormItems = [
       
    72 			{
       
    73 				name: 'source1',
       
    74 				type: 'filepicker',
       
    75 				filetype: 'media',
       
    76 				size: 40,
       
    77 				autofocus: true,
       
    78 				label: 'Source',
       
    79 				onchange: function(e) {
       
    80 					tinymce.each(e.meta, function(value, key) {
       
    81 						win.find('#' + key).value(value);
       
    82 					});
       
    83 				}
       
    84 			}
       
    85 		];
       
    86 
       
    87 		function recalcSize(e) {
       
    88 			var widthCtrl, heightCtrl, newWidth, newHeight;
       
    89 
       
    90 			widthCtrl = win.find('#width')[0];
       
    91 			heightCtrl = win.find('#height')[0];
       
    92 
       
    93 			newWidth = widthCtrl.value();
       
    94 			newHeight = heightCtrl.value();
       
    95 
       
    96 			if (win.find('#constrain')[0].checked() && width && height && newWidth && newHeight) {
       
    97 				if (e.control == widthCtrl) {
       
    98 					newHeight = Math.round((newWidth / width) * newHeight);
       
    99 
       
   100 					if (!isNaN(newHeight)) {
       
   101 						heightCtrl.value(newHeight);
       
   102 					}
       
   103 				} else {
       
   104 					newWidth = Math.round((newHeight / height) * newWidth);
       
   105 
       
   106 					if (!isNaN(newWidth)) {
       
   107 						widthCtrl.value(newWidth);
       
   108 					}
       
   109 				}
       
   110 			}
       
   111 
       
   112 			width = newWidth;
       
   113 			height = newHeight;
       
   114 		}
       
   115 
       
   116 		if (editor.settings.media_alt_source !== false) {
       
   117 			generalFormItems.push({name: 'source2', type: 'filepicker', filetype: 'media', size: 40, label: 'Alternative source'});
       
   118 		}
       
   119 
       
   120 		if (editor.settings.media_poster !== false) {
       
   121 			generalFormItems.push({name: 'poster', type: 'filepicker', filetype: 'image', size: 40, label: 'Poster'});
       
   122 		}
       
   123 
       
   124 		if (editor.settings.media_dimensions !== false) {
       
   125 			generalFormItems.push({
       
   126 				type: 'container',
       
   127 				label: 'Dimensions',
       
   128 				layout: 'flex',
       
   129 				align: 'center',
       
   130 				spacing: 5,
       
   131 				items: [
       
   132 					{name: 'width', type: 'textbox', maxLength: 5, size: 3, onchange: recalcSize, ariaLabel: 'Width'},
       
   133 					{type: 'label', text: 'x'},
       
   134 					{name: 'height', type: 'textbox', maxLength: 5, size: 3, onchange: recalcSize, ariaLabel: 'Height'},
       
   135 					{name: 'constrain', type: 'checkbox', checked: true, text: 'Constrain proportions'}
       
   136 				]
       
   137 			});
       
   138 		}
       
   139 
       
   140 		data = getData(editor.selection.getNode());
       
   141 		width = data.width;
       
   142 		height = data.height;
       
   143 
       
   144 		var embedTextBox = {
       
   145 			id: 'mcemediasource',
       
   146 			type: 'textbox',
       
   147 			flex: 1,
       
   148 			name: 'embed',
       
   149 			value: getSource(),
       
   150 			multiline: true,
       
   151 			label: 'Source'
       
   152 		};
       
   153 
       
   154 		function updateValueOnChange() {
       
   155 			data = htmlToData(this.value());
       
   156 			this.parent().parent().fromJSON(data);
       
   157 		}
       
   158 
       
   159 		embedTextBox[embedChange] = updateValueOnChange;
       
   160 
       
   161 		win = editor.windowManager.open({
       
   162 			title: 'Insert/edit video',
       
   163 			data: data,
       
   164 			bodyType: 'tabpanel',
       
   165 			body: [
       
   166 				{
       
   167 					title: 'General',
       
   168 					type: "form",
       
   169 					onShowTab: function() {
       
   170 						data = htmlToData(this.next().find('#embed').value());
       
   171 						this.fromJSON(data);
       
   172 					},
       
   173 					items: generalFormItems
       
   174 				},
       
   175 
       
   176 				{
       
   177 					title: 'Embed',
       
   178 					type: "panel",
       
   179 					layout: 'flex',
       
   180 					direction: 'column',
       
   181 					align: 'stretch',
       
   182 					padding: 10,
       
   183 					spacing: 10,
       
   184 					onShowTab: function() {
       
   185 						this.find('#embed').value(dataToHtml(this.parent().toJSON()));
       
   186 					},
       
   187 					items: [
       
   188 						{
       
   189 							type: 'label',
       
   190 							text: 'Paste your embed code below:',
       
   191 							forId: 'mcemediasource'
       
   192 						},
       
   193 						embedTextBox
       
   194 					]
       
   195 				}
       
   196 			],
       
   197 			onSubmit: function() {
       
   198 				var beforeObjects, afterObjects, i, y;
       
   199 
       
   200 				beforeObjects = editor.dom.select('img[data-mce-object]');
       
   201 				editor.insertContent(dataToHtml(this.toJSON()));
       
   202 				afterObjects = editor.dom.select('img[data-mce-object]');
       
   203 
       
   204 				// Find new image placeholder so we can select it
       
   205 				for (i = 0; i < beforeObjects.length; i++) {
       
   206 					for (y = afterObjects.length - 1; y >= 0; y--) {
       
   207 						if (beforeObjects[i] == afterObjects[y]) {
       
   208 							afterObjects.splice(y, 1);
       
   209 						}
       
   210 					}
       
   211 				}
       
   212 
       
   213 				editor.selection.select(afterObjects[0]);
       
   214 				editor.nodeChanged();
       
   215 			}
       
   216 		});
       
   217 	}
       
   218 
       
   219 	function getSource() {
       
   220 		var elm = editor.selection.getNode();
       
   221 
       
   222 		if (elm.getAttribute('data-mce-object')) {
       
   223 			return editor.selection.getContent();
       
   224 		}
       
   225 	}
       
   226 
       
   227 	function dataToHtml(data) {
       
   228 		var html = '';
       
   229 
       
   230 		if (!data.source1) {
       
   231 			tinymce.extend(data, htmlToData(data.embed));
       
   232 			if (!data.source1) {
       
   233 				return '';
       
   234 			}
       
   235 		}
       
   236 
       
   237 		if (!data.source2) {
       
   238 			data.source2 = '';
       
   239 		}
       
   240 
       
   241 		if (!data.poster) {
       
   242 			data.poster = '';
       
   243 		}
       
   244 
       
   245 		data.source1 = editor.convertURL(data.source1, "source");
       
   246 		data.source2 = editor.convertURL(data.source2, "source");
       
   247 		data.source1mime = guessMime(data.source1);
       
   248 		data.source2mime = guessMime(data.source2);
       
   249 		data.poster = editor.convertURL(data.poster, "poster");
       
   250 		data.flashPlayerUrl = editor.convertURL(url + '/moxieplayer.swf', "movie");
       
   251 
       
   252 		tinymce.each(urlPatterns, function(pattern) {
       
   253 			var match, i, url;
       
   254 
       
   255 			if ((match = pattern.regex.exec(data.source1))) {
       
   256 				url = pattern.url;
       
   257 
       
   258 				for (i = 0; match[i]; i++) {
       
   259 					/*jshint loopfunc:true*/
       
   260 					/*eslint no-loop-func:0 */
       
   261 					url = url.replace('$' + i, function() {
       
   262 						return match[i];
       
   263 					});
       
   264 				}
       
   265 
       
   266 				data.source1 = url;
       
   267 				data.type = pattern.type;
       
   268 				data.width = data.width || pattern.w;
       
   269 				data.height = data.height || pattern.h;
       
   270 			}
       
   271 		});
       
   272 
       
   273 		if (data.embed) {
       
   274 			html = updateHtml(data.embed, data, true);
       
   275 		} else {
       
   276 			var videoScript = getVideoScriptMatch(data.source1);
       
   277 			if (videoScript) {
       
   278 				data.type = 'script';
       
   279 				data.width = videoScript.width;
       
   280 				data.height = videoScript.height;
       
   281 			}
       
   282 
       
   283 			data.width = data.width || 300;
       
   284 			data.height = data.height || 150;
       
   285 
       
   286 			tinymce.each(data, function(value, key) {
       
   287 				data[key] = editor.dom.encode(value);
       
   288 			});
       
   289 
       
   290 			if (data.type == "iframe") {
       
   291 				html += '<iframe src="' + data.source1 + '" width="' + data.width + '" height="' + data.height + '"></iframe>';
       
   292 			} else if (data.source1mime == "application/x-shockwave-flash") {
       
   293 				html += '<object data="' + data.source1 + '" width="' + data.width + '" height="' + data.height + '" type="application/x-shockwave-flash">';
       
   294 
       
   295 				if (data.poster) {
       
   296 					html += '<img src="' + data.poster + '" width="' + data.width + '" height="' + data.height + '" />';
       
   297 				}
       
   298 
       
   299 				html += '</object>';
       
   300 			} else if (data.source1mime.indexOf('audio') != -1) {
       
   301 				if (editor.settings.audio_template_callback) {
       
   302 					html = editor.settings.audio_template_callback(data);
       
   303 				} else {
       
   304 					html += (
       
   305 						'<audio controls="controls" src="' + data.source1 + '">' +
       
   306 							(data.source2 ? '\n<source src="' + data.source2 + '"' + (data.source2mime ? ' type="' + data.source2mime + '"' : '') + ' />\n' : '') +
       
   307 						'</audio>'
       
   308 					);
       
   309 				}
       
   310 			} else if (data.type == "script") {
       
   311 				html += '<script src="' + data.source1 + '"></script>';
       
   312 			} else {
       
   313 				if (editor.settings.video_template_callback) {
       
   314 					html = editor.settings.video_template_callback(data);
       
   315 				} else {
       
   316 					html = (
       
   317 						'<video width="' + data.width + '" height="' + data.height + '"' + (data.poster ? ' poster="' + data.poster + '"' : '') + ' controls="controls">\n' +
       
   318 							'<source src="' + data.source1 + '"' + (data.source1mime ? ' type="' + data.source1mime + '"' : '') + ' />\n' +
       
   319 							(data.source2 ? '<source src="' + data.source2 + '"' + (data.source2mime ? ' type="' + data.source2mime + '"' : '') + ' />\n' : '') +
       
   320 						'</video>'
       
   321 					);
       
   322 				}
       
   323 			}
       
   324 		}
       
   325 
       
   326 		return html;
       
   327 	}
       
   328 
       
   329 	function htmlToData(html) {
       
   330 		var data = {};
       
   331 
       
   332 		new tinymce.html.SaxParser({
       
   333 			validate: false,
       
   334 			allow_conditional_comments: true,
       
   335 			special: 'script,noscript',
       
   336 			start: function(name, attrs) {
       
   337 				if (!data.source1 && name == "param") {
       
   338 					data.source1 = attrs.map.movie;
       
   339 				}
       
   340 
       
   341 				if (name == "iframe" || name == "object" || name == "embed" || name == "video" || name == "audio") {
       
   342 					if (!data.type) {
       
   343 						data.type = name;
       
   344 					}
       
   345 
       
   346 					data = tinymce.extend(attrs.map, data);
       
   347 				}
       
   348 
       
   349 				if (name == "script") {
       
   350 					var videoScript = getVideoScriptMatch(attrs.map.src);
       
   351 					if (!videoScript) {
       
   352 						return;
       
   353 					}
       
   354 
       
   355 					data = {
       
   356 						type: "script",
       
   357 						source1: attrs.map.src,
       
   358 						width: videoScript.width,
       
   359 						height: videoScript.height
       
   360 					};
       
   361 				}
       
   362 
       
   363 				if (name == "source") {
       
   364 					if (!data.source1) {
       
   365 						data.source1 = attrs.map.src;
       
   366 					} else if (!data.source2) {
       
   367 						data.source2 = attrs.map.src;
       
   368 					}
       
   369 				}
       
   370 
       
   371 				if (name == "img" && !data.poster) {
       
   372 					data.poster = attrs.map.src;
       
   373 				}
       
   374 			}
       
   375 		}).parse(html);
       
   376 
       
   377 		data.source1 = data.source1 || data.src || data.data;
       
   378 		data.source2 = data.source2 || '';
       
   379 		data.poster = data.poster || '';
       
   380 
       
   381 		return data;
       
   382 	}
       
   383 
       
   384 	function getData(element) {
       
   385 		if (element.getAttribute('data-mce-object')) {
       
   386 			return htmlToData(editor.serializer.serialize(element, {selection: true}));
       
   387 		}
       
   388 
       
   389 		return {};
       
   390 	}
       
   391 
       
   392 	function sanitize(html) {
       
   393 		if (editor.settings.media_filter_html === false) {
       
   394 			return html;
       
   395 		}
       
   396 
       
   397 		var writer = new tinymce.html.Writer();
       
   398 
       
   399 		new tinymce.html.SaxParser({
       
   400 			validate: false,
       
   401 			allow_conditional_comments: false,
       
   402 			special: 'script,noscript',
       
   403 
       
   404 			comment: function(text) {
       
   405 				writer.comment(text);
       
   406 			},
       
   407 
       
   408 			cdata: function(text) {
       
   409 				writer.cdata(text);
       
   410 			},
       
   411 
       
   412 			text: function(text, raw) {
       
   413 				writer.text(text, raw);
       
   414 			},
       
   415 
       
   416 			start: function(name, attrs, empty) {
       
   417 				if (name == 'script' || name == 'noscript') {
       
   418 					return;
       
   419 				}
       
   420 
       
   421 				for (var i = 0; i < attrs.length; i++) {
       
   422 					if (attrs[i].name.indexOf('on') === 0) {
       
   423 						return;
       
   424 					}
       
   425 				}
       
   426 
       
   427 				writer.start(name, attrs, empty);
       
   428 			},
       
   429 
       
   430 			end: function(name) {
       
   431 				if (name == 'script' || name == 'noscript') {
       
   432 					return;
       
   433 				}
       
   434 
       
   435 				writer.end(name);
       
   436 			}
       
   437 		}, new tinymce.html.Schema({})).parse(html);
       
   438 
       
   439 		return writer.getContent();
       
   440 	}
       
   441 
       
   442 	function updateHtml(html, data, updateAll) {
       
   443 		var writer = new tinymce.html.Writer();
       
   444 		var sourceCount = 0, hasImage;
       
   445 
       
   446 		function setAttributes(attrs, updatedAttrs) {
       
   447 			var name, i, value, attr;
       
   448 
       
   449 			for (name in updatedAttrs) {
       
   450 				value = "" + updatedAttrs[name];
       
   451 
       
   452 				if (attrs.map[name]) {
       
   453 					i = attrs.length;
       
   454 					while (i--) {
       
   455 						attr = attrs[i];
       
   456 
       
   457 						if (attr.name == name) {
       
   458 							if (value) {
       
   459 								attrs.map[name] = value;
       
   460 								attr.value = value;
       
   461 							} else {
       
   462 								delete attrs.map[name];
       
   463 								attrs.splice(i, 1);
       
   464 							}
       
   465 						}
       
   466 					}
       
   467 				} else if (value) {
       
   468 					attrs.push({
       
   469 						name: name,
       
   470 						value: value
       
   471 					});
       
   472 
       
   473 					attrs.map[name] = value;
       
   474 				}
       
   475 			}
       
   476 		}
       
   477 
       
   478 		new tinymce.html.SaxParser({
       
   479 			validate: false,
       
   480 			allow_conditional_comments: true,
       
   481 			special: 'script,noscript',
       
   482 
       
   483 			comment: function(text) {
       
   484 				writer.comment(text);
       
   485 			},
       
   486 
       
   487 			cdata: function(text) {
       
   488 				writer.cdata(text);
       
   489 			},
       
   490 
       
   491 			text: function(text, raw) {
       
   492 				writer.text(text, raw);
       
   493 			},
       
   494 
       
   495 			start: function(name, attrs, empty) {
       
   496 				switch (name) {
       
   497 					case "video":
       
   498 					case "object":
       
   499 					case "embed":
       
   500 					case "img":
       
   501 					case "iframe":
       
   502 						setAttributes(attrs, {
       
   503 							width: data.width,
       
   504 							height: data.height
       
   505 						});
       
   506 						break;
       
   507 				}
       
   508 
       
   509 				if (updateAll) {
       
   510 					switch (name) {
       
   511 						case "video":
       
   512 							setAttributes(attrs, {
       
   513 								poster: data.poster,
       
   514 								src: ""
       
   515 							});
       
   516 
       
   517 							if (data.source2) {
       
   518 								setAttributes(attrs, {
       
   519 									src: ""
       
   520 								});
       
   521 							}
       
   522 							break;
       
   523 
       
   524 						case "iframe":
       
   525 							setAttributes(attrs, {
       
   526 								src: data.source1
       
   527 							});
       
   528 							break;
       
   529 
       
   530 						case "source":
       
   531 							sourceCount++;
       
   532 
       
   533 							if (sourceCount <= 2) {
       
   534 								setAttributes(attrs, {
       
   535 									src: data["source" + sourceCount],
       
   536 									type: data["source" + sourceCount + "mime"]
       
   537 								});
       
   538 
       
   539 								if (!data["source" + sourceCount]) {
       
   540 									return;
       
   541 								}
       
   542 							}
       
   543 							break;
       
   544 
       
   545 						case "img":
       
   546 							if (!data.poster) {
       
   547 								return;
       
   548 							}
       
   549 
       
   550 							hasImage = true;
       
   551 							break;
       
   552 					}
       
   553 				}
       
   554 
       
   555 				writer.start(name, attrs, empty);
       
   556 			},
       
   557 
       
   558 			end: function(name) {
       
   559 				if (name == "video" && updateAll) {
       
   560 					for (var index = 1; index <= 2; index++) {
       
   561 						if (data["source" + index]) {
       
   562 							var attrs = [];
       
   563 							attrs.map = {};
       
   564 
       
   565 							if (sourceCount < index) {
       
   566 								setAttributes(attrs, {
       
   567 									src: data["source" + index],
       
   568 									type: data["source" + index + "mime"]
       
   569 								});
       
   570 
       
   571 								writer.start("source", attrs, true);
       
   572 							}
       
   573 						}
       
   574 					}
       
   575 				}
       
   576 
       
   577 				if (data.poster && name == "object" && updateAll && !hasImage) {
       
   578 					var imgAttrs = [];
       
   579 					imgAttrs.map = {};
       
   580 
       
   581 					setAttributes(imgAttrs, {
       
   582 						src: data.poster,
       
   583 						width: data.width,
       
   584 						height: data.height
       
   585 					});
       
   586 
       
   587 					writer.start("img", imgAttrs, true);
       
   588 				}
       
   589 
       
   590 				writer.end(name);
       
   591 			}
       
   592 		}, new tinymce.html.Schema({})).parse(html);
       
   593 
       
   594 		return writer.getContent();
       
   595 	}
       
   596 
       
   597 	editor.on('ResolveName', function(e) {
       
   598 		var name;
       
   599 
       
   600 		if (e.target.nodeType == 1 && (name = e.target.getAttribute("data-mce-object"))) {
       
   601 			e.name = name;
       
   602 		}
       
   603 	});
       
   604 
       
   605 	editor.on('preInit', function() {
       
   606 		// Make sure that any messy HTML is retained inside these
       
   607 		var specialElements = editor.schema.getSpecialElements();
       
   608 		tinymce.each('video audio iframe object'.split(' '), function(name) {
       
   609 			specialElements[name] = new RegExp('<\/' + name + '[^>]*>', 'gi');
       
   610 		});
       
   611 
       
   612 		// Allow elements
       
   613 		//editor.schema.addValidElements('object[id|style|width|height|classid|codebase|*],embed[id|style|width|height|type|src|*],video[*],audio[*]');
       
   614 
       
   615 		// Set allowFullscreen attribs as boolean
       
   616 		var boolAttrs = editor.schema.getBoolAttrs();
       
   617 		tinymce.each('webkitallowfullscreen mozallowfullscreen allowfullscreen'.split(' '), function(name) {
       
   618 			boolAttrs[name] = {};
       
   619 		});
       
   620 
       
   621 		// Converts iframe, video etc into placeholder images
       
   622 		editor.parser.addNodeFilter('iframe,video,audio,object,embed,script', function(nodes, name) {
       
   623 			var i = nodes.length, ai, node, placeHolder, attrName, attrValue, attribs, innerHtml;
       
   624 			var videoScript;
       
   625 
       
   626 			while (i--) {
       
   627 				node = nodes[i];
       
   628 				if (!node.parent) {
       
   629 					continue;
       
   630 				}
       
   631 
       
   632 				if (node.name == 'script') {
       
   633 					videoScript = getVideoScriptMatch(node.attr('src'));
       
   634 					if (!videoScript) {
       
   635 						continue;
       
   636 					}
       
   637 				}
       
   638 
       
   639 				placeHolder = new tinymce.html.Node('img', 1);
       
   640 				placeHolder.shortEnded = true;
       
   641 
       
   642 				if (videoScript) {
       
   643 					if (videoScript.width) {
       
   644 						node.attr('width', videoScript.width.toString());
       
   645 					}
       
   646 
       
   647 					if (videoScript.height) {
       
   648 						node.attr('height', videoScript.height.toString());
       
   649 					}
       
   650 				}
       
   651 
       
   652 				// Prefix all attributes except width, height and style since we
       
   653 				// will add these to the placeholder
       
   654 				attribs = node.attributes;
       
   655 				ai = attribs.length;
       
   656 				while (ai--) {
       
   657 					attrName = attribs[ai].name;
       
   658 					attrValue = attribs[ai].value;
       
   659 
       
   660 					if (attrName !== "width" && attrName !== "height" && attrName !== "style") {
       
   661 						if (attrName == "data" || attrName == "src") {
       
   662 							attrValue = editor.convertURL(attrValue, attrName);
       
   663 						}
       
   664 
       
   665 						placeHolder.attr('data-mce-p-' + attrName, attrValue);
       
   666 					}
       
   667 				}
       
   668 
       
   669 				// Place the inner HTML contents inside an escaped attribute
       
   670 				// This enables us to copy/paste the fake object
       
   671 				innerHtml = node.firstChild && node.firstChild.value;
       
   672 				if (innerHtml) {
       
   673 					placeHolder.attr("data-mce-html", escape(innerHtml));
       
   674 					placeHolder.firstChild = null;
       
   675 				}
       
   676 
       
   677 				placeHolder.attr({
       
   678 					width: node.attr('width') || "300",
       
   679 					height: node.attr('height') || (name == "audio" ? "30" : "150"),
       
   680 					style: node.attr('style'),
       
   681 					src: tinymce.Env.transparentSrc,
       
   682 					"data-mce-object": name,
       
   683 					"class": "mce-object mce-object-" + name
       
   684 				});
       
   685 
       
   686 				node.replace(placeHolder);
       
   687 			}
       
   688 		});
       
   689 
       
   690 		// Replaces placeholder images with real elements for video, object, iframe etc
       
   691 		editor.serializer.addAttributeFilter('data-mce-object', function(nodes, name) {
       
   692 			var i = nodes.length, node, realElm, ai, attribs, innerHtml, innerNode, realElmName;
       
   693 
       
   694 			while (i--) {
       
   695 				node = nodes[i];
       
   696 				if (!node.parent) {
       
   697 					continue;
       
   698 				}
       
   699 
       
   700 				realElmName = node.attr(name);
       
   701 				realElm = new tinymce.html.Node(realElmName, 1);
       
   702 
       
   703 				// Add width/height to everything but audio
       
   704 				if (realElmName != "audio" && realElmName != "script") {
       
   705 					realElm.attr({
       
   706 						width: node.attr('width'),
       
   707 						height: node.attr('height')
       
   708 					});
       
   709 				}
       
   710 
       
   711 				realElm.attr({
       
   712 					style: node.attr('style')
       
   713 				});
       
   714 
       
   715 				// Unprefix all placeholder attributes
       
   716 				attribs = node.attributes;
       
   717 				ai = attribs.length;
       
   718 				while (ai--) {
       
   719 					var attrName = attribs[ai].name;
       
   720 
       
   721 					if (attrName.indexOf('data-mce-p-') === 0) {
       
   722 						realElm.attr(attrName.substr(11), attribs[ai].value);
       
   723 					}
       
   724 				}
       
   725 
       
   726 				if (realElmName == "script") {
       
   727 					realElm.attr('type', 'text/javascript');
       
   728 				}
       
   729 
       
   730 				// Inject innerhtml
       
   731 				innerHtml = node.attr('data-mce-html');
       
   732 				if (innerHtml) {
       
   733 					innerNode = new tinymce.html.Node('#text', 3);
       
   734 					innerNode.raw = true;
       
   735 					innerNode.value = sanitize(unescape(innerHtml));
       
   736 					realElm.append(innerNode);
       
   737 				}
       
   738 
       
   739 				node.replace(realElm);
       
   740 			}
       
   741 		});
       
   742 	});
       
   743 
       
   744 	editor.on('ObjectSelected', function(e) {
       
   745 		var objectType = e.target.getAttribute('data-mce-object');
       
   746 
       
   747 		if (objectType == "audio" || objectType == "script") {
       
   748 			e.preventDefault();
       
   749 		}
       
   750 	});
       
   751 
       
   752 	editor.on('objectResized', function(e) {
       
   753 		var target = e.target, html;
       
   754 
       
   755 		if (target.getAttribute('data-mce-object')) {
       
   756 			html = target.getAttribute('data-mce-html');
       
   757 			if (html) {
       
   758 				html = unescape(html);
       
   759 				target.setAttribute('data-mce-html', escape(
       
   760 					updateHtml(html, {
       
   761 						width: e.width,
       
   762 						height: e.height
       
   763 					})
       
   764 				));
       
   765 			}
       
   766 		}
       
   767 	});
       
   768 
       
   769 	editor.addButton('media', {
       
   770 		tooltip: 'Insert/edit video',
       
   771 		onclick: showDialog,
       
   772 		stateSelector: ['img[data-mce-object=video]', 'img[data-mce-object=iframe]']
       
   773 	});
       
   774 
       
   775 	editor.addMenuItem('media', {
       
   776 		icon: 'media',
       
   777 		text: 'Insert/edit video',
       
   778 		onclick: showDialog,
       
   779 		context: 'insert',
       
   780 		prependToContext: true
       
   781 	});
       
   782 });