1(function () {
2var media = (function () {
3 'use strict';
4
5 var global = tinymce.util.Tools.resolve('tinymce.PluginManager');
6
7 var global$1 = tinymce.util.Tools.resolve('tinymce.Env');
8
9 var global$2 = tinymce.util.Tools.resolve('tinymce.util.Tools');
10
11 var getScripts = function (editor) {
12 return editor.getParam('media_scripts');
13 };
14 var getAudioTemplateCallback = function (editor) {
15 return editor.getParam('audio_template_callback');
16 };
17 var getVideoTemplateCallback = function (editor) {
18 return editor.getParam('video_template_callback');
19 };
20 var hasLiveEmbeds = function (editor) {
21 return editor.getParam('media_live_embeds', true);
22 };
23 var shouldFilterHtml = function (editor) {
24 return editor.getParam('media_filter_html', true);
25 };
26 var getUrlResolver = function (editor) {
27 return editor.getParam('media_url_resolver');
28 };
29 var hasAltSource = function (editor) {
30 return editor.getParam('media_alt_source', true);
31 };
32 var hasPoster = function (editor) {
33 return editor.getParam('media_poster', true);
34 };
35 var hasDimensions = function (editor) {
36 return editor.getParam('media_dimensions', true);
37 };
38 var Settings = {
39 getScripts: getScripts,
40 getAudioTemplateCallback: getAudioTemplateCallback,
41 getVideoTemplateCallback: getVideoTemplateCallback,
42 hasLiveEmbeds: hasLiveEmbeds,
43 shouldFilterHtml: shouldFilterHtml,
44 getUrlResolver: getUrlResolver,
45 hasAltSource: hasAltSource,
46 hasPoster: hasPoster,
47 hasDimensions: hasDimensions
48 };
49
50 var Cell = function (initial) {
51 var value = initial;
52 var get = function () {
53 return value;
54 };
55 var set = function (v) {
56 value = v;
57 };
58 var clone = function () {
59 return Cell(get());
60 };
61 return {
62 get: get,
63 set: set,
64 clone: clone
65 };
66 };
67
68 var noop = function () {
69 };
70 var constant = function (value) {
71 return function () {
72 return value;
73 };
74 };
75 var never = constant(false);
76 var always = constant(true);
77
78 var none = function () {
79 return NONE;
80 };
81 var NONE = function () {
82 var eq = function (o) {
83 return o.isNone();
84 };
85 var call = function (thunk) {
86 return thunk();
87 };
88 var id = function (n) {
89 return n;
90 };
91 var me = {
92 fold: function (n, s) {
93 return n();
94 },
95 is: never,
96 isSome: never,
97 isNone: always,
98 getOr: id,
99 getOrThunk: call,
100 getOrDie: function (msg) {
101 throw new Error(msg || 'error: getOrDie called on none.');
102 },
103 getOrNull: constant(null),
104 getOrUndefined: constant(undefined),
105 or: id,
106 orThunk: call,
107 map: none,
108 each: noop,
109 bind: none,
110 exists: never,
111 forall: always,
112 filter: none,
113 equals: eq,
114 equals_: eq,
115 toArray: function () {
116 return [];
117 },
118 toString: constant('none()')
119 };
120 if (Object.freeze) {
121 Object.freeze(me);
122 }
123 return me;
124 }();
125 var some = function (a) {
126 var constant_a = constant(a);
127 var self = function () {
128 return me;
129 };
130 var bind = function (f) {
131 return f(a);
132 };
133 var me = {
134 fold: function (n, s) {
135 return s(a);
136 },
137 is: function (v) {
138 return a === v;
139 },
140 isSome: always,
141 isNone: never,
142 getOr: constant_a,
143 getOrThunk: constant_a,
144 getOrDie: constant_a,
145 getOrNull: constant_a,
146 getOrUndefined: constant_a,
147 or: self,
148 orThunk: self,
149 map: function (f) {
150 return some(f(a));
151 },
152 each: function (f) {
153 f(a);
154 },
155 bind: bind,
156 exists: bind,
157 forall: bind,
158 filter: function (f) {
159 return f(a) ? me : NONE;
160 },
161 toArray: function () {
162 return [a];
163 },
164 toString: function () {
165 return 'some(' + a + ')';
166 },
167 equals: function (o) {
168 return o.is(a);
169 },
170 equals_: function (o, elementEq) {
171 return o.fold(never, function (b) {
172 return elementEq(a, b);
173 });
174 }
175 };
176 return me;
177 };
178 var from = function (value) {
179 return value === null || value === undefined ? NONE : some(value);
180 };
181 var Option = {
182 some: some,
183 none: none,
184 from: from
185 };
186
187 var hasOwnProperty = Object.hasOwnProperty;
188 var get = function (obj, key) {
189 return has(obj, key) ? Option.from(obj[key]) : Option.none();
190 };
191 var has = function (obj, key) {
192 return hasOwnProperty.call(obj, key);
193 };
194
195 var global$3 = tinymce.util.Tools.resolve('tinymce.dom.DOMUtils');
196
197 var global$4 = tinymce.util.Tools.resolve('tinymce.html.SaxParser');
198
199 var getVideoScriptMatch = function (prefixes, src) {
200 if (prefixes) {
201 for (var i = 0; i < prefixes.length; i++) {
202 if (src.indexOf(prefixes[i].filter) !== -1) {
203 return prefixes[i];
204 }
205 }
206 }
207 };
208 var VideoScript = { getVideoScriptMatch: getVideoScriptMatch };
209
210 var DOM = global$3.DOM;
211 var trimPx = function (value) {
212 return value.replace(/px$/, '');
213 };
214 var getEphoxEmbedData = function (attrs) {
215 var style = attrs.map.style;
216 var styles = style ? DOM.parseStyle(style) : {};
217 return {
218 type: 'ephox-embed-iri',
219 source1: attrs.map['data-ephox-embed-iri'],
220 source2: '',
221 poster: '',
222 width: get(styles, 'max-width').map(trimPx).getOr(''),
223 height: get(styles, 'max-height').map(trimPx).getOr('')
224 };
225 };
226 var htmlToData = function (prefixes, html) {
227 var isEphoxEmbed = Cell(false);
228 var data = {};
229 global$4({
230 validate: false,
231 allow_conditional_comments: true,
232 special: 'script,noscript',
233 start: function (name, attrs) {
234 if (isEphoxEmbed.get()) ; else if (has(attrs.map, 'data-ephox-embed-iri')) {
235 isEphoxEmbed.set(true);
236 data = getEphoxEmbedData(attrs);
237 } else {
238 if (!data.source1 && name === 'param') {
239 data.source1 = attrs.map.movie;
240 }
241 if (name === 'iframe' || name === 'object' || name === 'embed' || name === 'video' || name === 'audio') {
242 if (!data.type) {
243 data.type = name;
244 }
245 data = global$2.extend(attrs.map, data);
246 }
247 if (name === 'script') {
248 var videoScript = VideoScript.getVideoScriptMatch(prefixes, attrs.map.src);
249 if (!videoScript) {
250 return;
251 }
252 data = {
253 type: 'script',
254 source1: attrs.map.src,
255 width: videoScript.width,
256 height: videoScript.height
257 };
258 }
259 if (name === 'source') {
260 if (!data.source1) {
261 data.source1 = attrs.map.src;
262 } else if (!data.source2) {
263 data.source2 = attrs.map.src;
264 }
265 }
266 if (name === 'img' && !data.poster) {
267 data.poster = attrs.map.src;
268 }
269 }
270 }
271 }).parse(html);
272 data.source1 = data.source1 || data.src || data.data;
273 data.source2 = data.source2 || '';
274 data.poster = data.poster || '';
275 return data;
276 };
277 var HtmlToData = { htmlToData: htmlToData };
278
279 var global$5 = tinymce.util.Tools.resolve('tinymce.util.Promise');
280
281 var guess = function (url) {
282 var mimes = {
283 mp3: 'audio/mpeg',
284 wav: 'audio/wav',
285 mp4: 'video/mp4',
286 webm: 'video/webm',
287 ogg: 'video/ogg',
288 swf: 'application/x-shockwave-flash'
289 };
290 var fileEnd = url.toLowerCase().split('.').pop();
291 var mime = mimes[fileEnd];
292 return mime ? mime : '';
293 };
294 var Mime = { guess: guess };
295
296 var global$6 = tinymce.util.Tools.resolve('tinymce.html.Schema');
297
298 var global$7 = tinymce.util.Tools.resolve('tinymce.html.Writer');
299
300 var DOM$1 = global$3.DOM;
301 var addPx = function (value) {
302 return /^[0-9.]+$/.test(value) ? value + 'px' : value;
303 };
304 var setAttributes = function (attrs, updatedAttrs) {
305 for (var name in updatedAttrs) {
306 var value = '' + updatedAttrs[name];
307 if (attrs.map[name]) {
308 var i = attrs.length;
309 while (i--) {
310 var attr = attrs[i];
311 if (attr.name === name) {
312 if (value) {
313 attrs.map[name] = value;
314 attr.value = value;
315 } else {
316 delete attrs.map[name];
317 attrs.splice(i, 1);
318 }
319 }
320 }
321 } else if (value) {
322 attrs.push({
323 name: name,
324 value: value
325 });
326 attrs.map[name] = value;
327 }
328 }
329 };
330 var updateEphoxEmbed = function (data, attrs) {
331 var style = attrs.map.style;
332 var styleMap = style ? DOM$1.parseStyle(style) : {};
333 styleMap['max-width'] = addPx(data.width);
334 styleMap['max-height'] = addPx(data.height);
335 setAttributes(attrs, { style: DOM$1.serializeStyle(styleMap) });
336 };
337 var updateHtml = function (html, data, updateAll) {
338 var writer = global$7();
339 var isEphoxEmbed = Cell(false);
340 var sourceCount = 0;
341 var hasImage;
342 global$4({
343 validate: false,
344 allow_conditional_comments: true,
345 special: 'script,noscript',
346 comment: function (text) {
347 writer.comment(text);
348 },
349 cdata: function (text) {
350 writer.cdata(text);
351 },
352 text: function (text, raw) {
353 writer.text(text, raw);
354 },
355 start: function (name, attrs, empty) {
356 if (isEphoxEmbed.get()) ; else if (has(attrs.map, 'data-ephox-embed-iri')) {
357 isEphoxEmbed.set(true);
358 updateEphoxEmbed(data, attrs);
359 } else {
360 switch (name) {
361 case 'video':
362 case 'object':
363 case 'embed':
364 case 'img':
365 case 'iframe':
366 if (data.height !== undefined && data.width !== undefined) {
367 setAttributes(attrs, {
368 width: data.width,
369 height: data.height
370 });
371 }
372 break;
373 }
374 if (updateAll) {
375 switch (name) {
376 case 'video':
377 setAttributes(attrs, {
378 poster: data.poster,
379 src: ''
380 });
381 if (data.source2) {
382 setAttributes(attrs, { src: '' });
383 }
384 break;
385 case 'iframe':
386 setAttributes(attrs, { src: data.source1 });
387 break;
388 case 'source':
389 sourceCount++;
390 if (sourceCount <= 2) {
391 setAttributes(attrs, {
392 src: data['source' + sourceCount],
393 type: data['source' + sourceCount + 'mime']
394 });
395 if (!data['source' + sourceCount]) {
396 return;
397 }
398 }
399 break;
400 case 'img':
401 if (!data.poster) {
402 return;
403 }
404 hasImage = true;
405 break;
406 }
407 }
408 }
409 writer.start(name, attrs, empty);
410 },
411 end: function (name) {
412 if (!isEphoxEmbed.get()) {
413 if (name === 'video' && updateAll) {
414 for (var index = 1; index <= 2; index++) {
415 if (data['source' + index]) {
416 var attrs = [];
417 attrs.map = {};
418 if (sourceCount < index) {
419 setAttributes(attrs, {
420 src: data['source' + index],
421 type: data['source' + index + 'mime']
422 });
423 writer.start('source', attrs, true);
424 }
425 }
426 }
427 }
428 if (data.poster && name === 'object' && updateAll && !hasImage) {
429 var imgAttrs = [];
430 imgAttrs.map = {};
431 setAttributes(imgAttrs, {
432 src: data.poster,
433 width: data.width,
434 height: data.height
435 });
436 writer.start('img', imgAttrs, true);
437 }
438 }
439 writer.end(name);
440 }
441 }, global$6({})).parse(html);
442 return writer.getContent();
443 };
444 var UpdateHtml = { updateHtml: updateHtml };
445
446 var urlPatterns = [
447 {
448 regex: /youtu\.be\/([\w\-_\?&=.]+)/i,
449 type: 'iframe',
450 w: 560,
451 h: 314,
452 url: '//www.youtube.com/embed/$1',
453 allowFullscreen: true
454 },
455 {
456 regex: /youtube\.com(.+)v=([^&]+)(&([a-z0-9&=\-_]+))?/i,
457 type: 'iframe',
458 w: 560,
459 h: 314,
460 url: '//www.youtube.com/embed/$2?$4',
461 allowFullscreen: true
462 },
463 {
464 regex: /youtube.com\/embed\/([a-z0-9\?&=\-_]+)/i,
465 type: 'iframe',
466 w: 560,
467 h: 314,
468 url: '//www.youtube.com/embed/$1',
469 allowFullscreen: true
470 },
471 {
472 regex: /vimeo\.com\/([0-9]+)/,
473 type: 'iframe',
474 w: 425,
475 h: 350,
476 url: '//player.vimeo.com/video/$1?title=0&byline=0&portrait=0&color=8dc7dc',
477 allowFullscreen: true
478 },
479 {
480 regex: /vimeo\.com\/(.*)\/([0-9]+)/,
481 type: 'iframe',
482 w: 425,
483 h: 350,
484 url: '//player.vimeo.com/video/$2?title=0&byline=0',
485 allowFullscreen: true
486 },
487 {
488 regex: /maps\.google\.([a-z]{2,3})\/maps\/(.+)msid=(.+)/,
489 type: 'iframe',
490 w: 425,
491 h: 350,
492 url: '//maps.google.com/maps/ms?msid=$2&output=embed"',
493 allowFullscreen: false
494 },
495 {
496 regex: /dailymotion\.com\/video\/([^_]+)/,
497 type: 'iframe',
498 w: 480,
499 h: 270,
500 url: '//www.dailymotion.com/embed/video/$1',
501 allowFullscreen: true
502 },
503 {
504 regex: /dai\.ly\/([^_]+)/,
505 type: 'iframe',
506 w: 480,
507 h: 270,
508 url: '//www.dailymotion.com/embed/video/$1',
509 allowFullscreen: true
510 }
511 ];
512 var getUrl = function (pattern, url) {
513 var match = pattern.regex.exec(url);
514 var newUrl = pattern.url;
515 var _loop_1 = function (i) {
516 newUrl = newUrl.replace('$' + i, function () {
517 return match[i] ? match[i] : '';
518 });
519 };
520 for (var i = 0; i < match.length; i++) {
521 _loop_1(i);
522 }
523 return newUrl.replace(/\?$/, '');
524 };
525 var matchPattern = function (url) {
526 var pattern = urlPatterns.filter(function (pattern) {
527 return pattern.regex.test(url);
528 });
529 if (pattern.length > 0) {
530 return global$2.extend({}, pattern[0], { url: getUrl(pattern[0], url) });
531 } else {
532 return null;
533 }
534 };
535
536 var getIframeHtml = function (data) {
537 var allowFullscreen = data.allowFullscreen ? ' allowFullscreen="1"' : '';
538 return '<iframe src="' + data.source1 + '" width="' + data.width + '" height="' + data.height + '"' + allowFullscreen + '></iframe>';
539 };
540 var getFlashHtml = function (data) {
541 var html = '<object data="' + data.source1 + '" width="' + data.width + '" height="' + data.height + '" type="application/x-shockwave-flash">';
542 if (data.poster) {
543 html += '<img src="' + data.poster + '" width="' + data.width + '" height="' + data.height + '" />';
544 }
545 html += '</object>';
546 return html;
547 };
548 var getAudioHtml = function (data, audioTemplateCallback) {
549 if (audioTemplateCallback) {
550 return audioTemplateCallback(data);
551 } else {
552 return '<audio controls="controls" src="' + data.source1 + '">' + (data.source2 ? '\n<source src="' + data.source2 + '"' + (data.source2mime ? ' type="' + data.source2mime + '"' : '') + ' />\n' : '') + '</audio>';
553 }
554 };
555 var getVideoHtml = function (data, videoTemplateCallback) {
556 if (videoTemplateCallback) {
557 return videoTemplateCallback(data);
558 } else {
559 return '<video width="' + data.width + '" height="' + data.height + '"' + (data.poster ? ' poster="' + data.poster + '"' : '') + ' controls="controls">\n' + '<source src="' + data.source1 + '"' + (data.source1mime ? ' type="' + data.source1mime + '"' : '') + ' />\n' + (data.source2 ? '<source src="' + data.source2 + '"' + (data.source2mime ? ' type="' + data.source2mime + '"' : '') + ' />\n' : '') + '</video>';
560 }
561 };
562 var getScriptHtml = function (data) {
563 return '<script src="' + data.source1 + '"></script>';
564 };
565 var dataToHtml = function (editor, dataIn) {
566 var data = global$2.extend({}, dataIn);
567 if (!data.source1) {
568 global$2.extend(data, HtmlToData.htmlToData(Settings.getScripts(editor), data.embed));
569 if (!data.source1) {
570 return '';
571 }
572 }
573 if (!data.source2) {
574 data.source2 = '';
575 }
576 if (!data.poster) {
577 data.poster = '';
578 }
579 data.source1 = editor.convertURL(data.source1, 'source');
580 data.source2 = editor.convertURL(data.source2, 'source');
581 data.source1mime = Mime.guess(data.source1);
582 data.source2mime = Mime.guess(data.source2);
583 data.poster = editor.convertURL(data.poster, 'poster');
584 var pattern = matchPattern(data.source1);
585 if (pattern) {
586 data.source1 = pattern.url;
587 data.type = pattern.type;
588 data.allowFullscreen = pattern.allowFullscreen;
589 data.width = data.width || pattern.w;
590 data.height = data.height || pattern.h;
591 }
592 if (data.embed) {
593 return UpdateHtml.updateHtml(data.embed, data, true);
594 } else {
595 var videoScript = VideoScript.getVideoScriptMatch(Settings.getScripts(editor), data.source1);
596 if (videoScript) {
597 data.type = 'script';
598 data.width = videoScript.width;
599 data.height = videoScript.height;
600 }
601 var audioTemplateCallback = Settings.getAudioTemplateCallback(editor);
602 var videoTemplateCallback = Settings.getVideoTemplateCallback(editor);
603 data.width = data.width || 300;
604 data.height = data.height || 150;
605 global$2.each(data, function (value, key) {
606 data[key] = editor.dom.encode(value);
607 });
608 if (data.type === 'iframe') {
609 return getIframeHtml(data);
610 } else if (data.source1mime === 'application/x-shockwave-flash') {
611 return getFlashHtml(data);
612 } else if (data.source1mime.indexOf('audio') !== -1) {
613 return getAudioHtml(data, audioTemplateCallback);
614 } else if (data.type === 'script') {
615 return getScriptHtml(data);
616 } else {
617 return getVideoHtml(data, videoTemplateCallback);
618 }
619 }
620 };
621 var DataToHtml = { dataToHtml: dataToHtml };
622
623 var cache = {};
624 var embedPromise = function (data, dataToHtml, handler) {
625 return new global$5(function (res, rej) {
626 var wrappedResolve = function (response) {
627 if (response.html) {
628 cache[data.source1] = response;
629 }
630 return res({
631 url: data.source1,
632 html: response.html ? response.html : dataToHtml(data)
633 });
634 };
635 if (cache[data.source1]) {
636 wrappedResolve(cache[data.source1]);
637 } else {
638 handler({ url: data.source1 }, wrappedResolve, rej);
639 }
640 });
641 };
642 var defaultPromise = function (data, dataToHtml) {
643 return new global$5(function (res) {
644 res({
645 html: dataToHtml(data),
646 url: data.source1
647 });
648 });
649 };
650 var loadedData = function (editor) {
651 return function (data) {
652 return DataToHtml.dataToHtml(editor, data);
653 };
654 };
655 var getEmbedHtml = function (editor, data) {
656 var embedHandler = Settings.getUrlResolver(editor);
657 return embedHandler ? embedPromise(data, loadedData(editor), embedHandler) : defaultPromise(data, loadedData(editor));
658 };
659 var isCached = function (url) {
660 return cache.hasOwnProperty(url);
661 };
662 var Service = {
663 getEmbedHtml: getEmbedHtml,
664 isCached: isCached
665 };
666
667 var trimPx$1 = function (value) {
668 return value.replace(/px$/, '');
669 };
670 var addPx$1 = function (value) {
671 return /^[0-9.]+$/.test(value) ? value + 'px' : value;
672 };
673 var getSize = function (name) {
674 return function (elm) {
675 return elm ? trimPx$1(elm.style[name]) : '';
676 };
677 };
678 var setSize = function (name) {
679 return function (elm, value) {
680 if (elm) {
681 elm.style[name] = addPx$1(value);
682 }
683 };
684 };
685 var Size = {
686 getMaxWidth: getSize('maxWidth'),
687 getMaxHeight: getSize('maxHeight'),
688 setMaxWidth: setSize('maxWidth'),
689 setMaxHeight: setSize('maxHeight')
690 };
691
692 var doSyncSize = function (widthCtrl, heightCtrl) {
693 widthCtrl.state.set('oldVal', widthCtrl.value());
694 heightCtrl.state.set('oldVal', heightCtrl.value());
695 };
696 var doSizeControls = function (win, f) {
697 var widthCtrl = win.find('#width')[0];
698 var heightCtrl = win.find('#height')[0];
699 var constrained = win.find('#constrain')[0];
700 if (widthCtrl && heightCtrl && constrained) {
701 f(widthCtrl, heightCtrl, constrained.checked());
702 }
703 };
704 var doUpdateSize = function (widthCtrl, heightCtrl, isContrained) {
705 var oldWidth = widthCtrl.state.get('oldVal');
706 var oldHeight = heightCtrl.state.get('oldVal');
707 var newWidth = widthCtrl.value();
708 var newHeight = heightCtrl.value();
709 if (isContrained && oldWidth && oldHeight && newWidth && newHeight) {
710 if (newWidth !== oldWidth) {
711 newHeight = Math.round(newWidth / oldWidth * newHeight);
712 if (!isNaN(newHeight)) {
713 heightCtrl.value(newHeight);
714 }
715 } else {
716 newWidth = Math.round(newHeight / oldHeight * newWidth);
717 if (!isNaN(newWidth)) {
718 widthCtrl.value(newWidth);
719 }
720 }
721 }
722 doSyncSize(widthCtrl, heightCtrl);
723 };
724 var syncSize = function (win) {
725 doSizeControls(win, doSyncSize);
726 };
727 var updateSize = function (win) {
728 doSizeControls(win, doUpdateSize);
729 };
730 var createUi = function (onChange) {
731 var recalcSize = function () {
732 onChange(function (win) {
733 updateSize(win);
734 });
735 };
736 return {
737 type: 'container',
738 label: 'Dimensions',
739 layout: 'flex',
740 align: 'center',
741 spacing: 5,
742 items: [
743 {
744 name: 'width',
745 type: 'textbox',
746 maxLength: 5,
747 size: 5,
748 onchange: recalcSize,
749 ariaLabel: 'Width'
750 },
751 {
752 type: 'label',
753 text: 'x'
754 },
755 {
756 name: 'height',
757 type: 'textbox',
758 maxLength: 5,
759 size: 5,
760 onchange: recalcSize,
761 ariaLabel: 'Height'
762 },
763 {
764 name: 'constrain',
765 type: 'checkbox',
766 checked: true,
767 text: 'Constrain proportions'
768 }
769 ]
770 };
771 };
772 var SizeManager = {
773 createUi: createUi,
774 syncSize: syncSize,
775 updateSize: updateSize
776 };
777
778 var embedChange = global$1.ie && global$1.ie <= 8 ? 'onChange' : 'onInput';
779 var handleError = function (editor) {
780 return function (error) {
781 var errorMessage = error && error.msg ? 'Media embed handler error: ' + error.msg : 'Media embed handler threw unknown error.';
782 editor.notificationManager.open({
783 type: 'error',
784 text: errorMessage
785 });
786 };
787 };
788 var getData = function (editor) {
789 var element = editor.selection.getNode();
790 var dataEmbed = element.getAttribute('data-ephox-embed-iri');
791 if (dataEmbed) {
792 return {
793 'source1': dataEmbed,
794 'data-ephox-embed-iri': dataEmbed,
795 'width': Size.getMaxWidth(element),
796 'height': Size.getMaxHeight(element)
797 };
798 }
799 return element.getAttribute('data-mce-object') ? HtmlToData.htmlToData(Settings.getScripts(editor), editor.serializer.serialize(element, { selection: true })) : {};
800 };
801 var getSource = function (editor) {
802 var elm = editor.selection.getNode();
803 if (elm.getAttribute('data-mce-object') || elm.getAttribute('data-ephox-embed-iri')) {
804 return editor.selection.getContent();
805 }
806 };
807 var addEmbedHtml = function (win, editor) {
808 return function (response) {
809 var html = response.html;
810 var embed = win.find('#embed')[0];
811 var data = global$2.extend(HtmlToData.htmlToData(Settings.getScripts(editor), html), { source1: response.url });
812 win.fromJSON(data);
813 if (embed) {
814 embed.value(html);
815 SizeManager.updateSize(win);
816 }
817 };
818 };
819 var selectPlaceholder = function (editor, beforeObjects) {
820 var i;
821 var y;
822 var afterObjects = editor.dom.select('img[data-mce-object]');
823 for (i = 0; i < beforeObjects.length; i++) {
824 for (y = afterObjects.length - 1; y >= 0; y--) {
825 if (beforeObjects[i] === afterObjects[y]) {
826 afterObjects.splice(y, 1);
827 }
828 }
829 }
830 editor.selection.select(afterObjects[0]);
831 };
832 var handleInsert = function (editor, html) {
833 var beforeObjects = editor.dom.select('img[data-mce-object]');
834 editor.insertContent(html);
835 selectPlaceholder(editor, beforeObjects);
836 editor.nodeChanged();
837 };
838 var submitForm = function (win, editor) {
839 var data = win.toJSON();
840 data.embed = UpdateHtml.updateHtml(data.embed, data);
841 if (data.embed && Service.isCached(data.source1)) {
842 handleInsert(editor, data.embed);
843 } else {
844 Service.getEmbedHtml(editor, data).then(function (response) {
845 handleInsert(editor, response.html);
846 }).catch(handleError(editor));
847 }
848 };
849 var populateMeta = function (win, meta) {
850 global$2.each(meta, function (value, key) {
851 win.find('#' + key).value(value);
852 });
853 };
854 var showDialog = function (editor) {
855 var win;
856 var data;
857 var generalFormItems = [{
858 name: 'source1',
859 type: 'filepicker',
860 filetype: 'media',
861 size: 40,
862 autofocus: true,
863 label: 'Source',
864 onpaste: function () {
865 setTimeout(function () {
866 Service.getEmbedHtml(editor, win.toJSON()).then(addEmbedHtml(win, editor)).catch(handleError(editor));
867 }, 1);
868 },
869 onchange: function (e) {
870 Service.getEmbedHtml(editor, win.toJSON()).then(addEmbedHtml(win, editor)).catch(handleError(editor));
871 populateMeta(win, e.meta);
872 },
873 onbeforecall: function (e) {
874 e.meta = win.toJSON();
875 }
876 }];
877 var advancedFormItems = [];
878 var reserialise = function (update) {
879 update(win);
880 data = win.toJSON();
881 win.find('#embed').value(UpdateHtml.updateHtml(data.embed, data));
882 };
883 if (Settings.hasAltSource(editor)) {
884 advancedFormItems.push({
885 name: 'source2',
886 type: 'filepicker',
887 filetype: 'media',
888 size: 40,
889 label: 'Alternative source'
890 });
891 }
892 if (Settings.hasPoster(editor)) {
893 advancedFormItems.push({
894 name: 'poster',
895 type: 'filepicker',
896 filetype: 'image',
897 size: 40,
898 label: 'Poster'
899 });
900 }
901 if (Settings.hasDimensions(editor)) {
902 var control = SizeManager.createUi(reserialise);
903 generalFormItems.push(control);
904 }
905 data = getData(editor);
906 var embedTextBox = {
907 id: 'mcemediasource',
908 type: 'textbox',
909 flex: 1,
910 name: 'embed',
911 value: getSource(editor),
912 multiline: true,
913 rows: 5,
914 label: 'Source'
915 };
916 var updateValueOnChange = function () {
917 data = global$2.extend({}, HtmlToData.htmlToData(Settings.getScripts(editor), this.value()));
918 this.parent().parent().fromJSON(data);
919 };
920 embedTextBox[embedChange] = updateValueOnChange;
921 var body = [
922 {
923 title: 'General',
924 type: 'form',
925 items: generalFormItems
926 },
927 {
928 title: 'Embed',
929 type: 'container',
930 layout: 'flex',
931 direction: 'column',
932 align: 'stretch',
933 padding: 10,
934 spacing: 10,
935 items: [
936 {
937 type: 'label',
938 text: 'Paste your embed code below:',
939 forId: 'mcemediasource'
940 },
941 embedTextBox
942 ]
943 }
944 ];
945 if (advancedFormItems.length > 0) {
946 body.push({
947 title: 'Advanced',
948 type: 'form',
949 items: advancedFormItems
950 });
951 }
952 win = editor.windowManager.open({
953 title: 'Insert/edit media',
954 data: data,
955 bodyType: 'tabpanel',
956 body: body,
957 onSubmit: function () {
958 SizeManager.updateSize(win);
959 submitForm(win, editor);
960 }
961 });
962 SizeManager.syncSize(win);
963 };
964 var Dialog = { showDialog: showDialog };
965
966 var get$1 = function (editor) {
967 var showDialog = function () {
968 Dialog.showDialog(editor);
969 };
970 return { showDialog: showDialog };
971 };
972 var Api = { get: get$1 };
973
974 var register = function (editor) {
975 var showDialog = function () {
976 Dialog.showDialog(editor);
977 };
978 editor.addCommand('mceMedia', showDialog);
979 };
980 var Commands = { register: register };
981
982 var global$8 = tinymce.util.Tools.resolve('tinymce.html.Node');
983
984 var sanitize = function (editor, html) {
985 if (Settings.shouldFilterHtml(editor) === false) {
986 return html;
987 }
988 var writer = global$7();
989 var blocked;
990 global$4({
991 validate: false,
992 allow_conditional_comments: false,
993 special: 'script,noscript',
994 comment: function (text) {
995 writer.comment(text);
996 },
997 cdata: function (text) {
998 writer.cdata(text);
999 },
1000 text: function (text, raw) {
1001 writer.text(text, raw);
1002 },
1003 start: function (name, attrs, empty) {
1004 blocked = true;
1005 if (name === 'script' || name === 'noscript' || name === 'svg') {
1006 return;
1007 }
1008 for (var i = attrs.length - 1; i >= 0; i--) {
1009 var attrName = attrs[i].name;
1010 if (attrName.indexOf('on') === 0) {
1011 delete attrs.map[attrName];
1012 attrs.splice(i, 1);
1013 }
1014 if (attrName === 'style') {
1015 attrs[i].value = editor.dom.serializeStyle(editor.dom.parseStyle(attrs[i].value), name);
1016 }
1017 }
1018 writer.start(name, attrs, empty);
1019 blocked = false;
1020 },
1021 end: function (name) {
1022 if (blocked) {
1023 return;
1024 }
1025 writer.end(name);
1026 }
1027 }, global$6({})).parse(html);
1028 return writer.getContent();
1029 };
1030 var Sanitize = { sanitize: sanitize };
1031
1032 var createPlaceholderNode = function (editor, node) {
1033 var placeHolder;
1034 var name = node.name;
1035 placeHolder = new global$8('img', 1);
1036 placeHolder.shortEnded = true;
1037 retainAttributesAndInnerHtml(editor, node, placeHolder);
1038 placeHolder.attr({
1039 'width': node.attr('width') || '300',
1040 'height': node.attr('height') || (name === 'audio' ? '30' : '150'),
1041 'style': node.attr('style'),
1042 'src': global$1.transparentSrc,
1043 'data-mce-object': name,
1044 'class': 'mce-object mce-object-' + name
1045 });
1046 return placeHolder;
1047 };
1048 var createPreviewIframeNode = function (editor, node) {
1049 var previewWrapper;
1050 var previewNode;
1051 var shimNode;
1052 var name = node.name;
1053 previewWrapper = new global$8('span', 1);
1054 previewWrapper.attr({
1055 'contentEditable': 'false',
1056 'style': node.attr('style'),
1057 'data-mce-object': name,
1058 'class': 'mce-preview-object mce-object-' + name
1059 });
1060 retainAttributesAndInnerHtml(editor, node, previewWrapper);
1061 previewNode = new global$8(name, 1);
1062 previewNode.attr({
1063 src: node.attr('src'),
1064 allowfullscreen: node.attr('allowfullscreen'),
1065 style: node.attr('style'),
1066 class: node.attr('class'),
1067 width: node.attr('width'),
1068 height: node.attr('height'),
1069 frameborder: '0'
1070 });
1071 shimNode = new global$8('span', 1);
1072 shimNode.attr('class', 'mce-shim');
1073 previewWrapper.append(previewNode);
1074 previewWrapper.append(shimNode);
1075 return previewWrapper;
1076 };
1077 var retainAttributesAndInnerHtml = function (editor, sourceNode, targetNode) {
1078 var attrName;
1079 var attrValue;
1080 var attribs;
1081 var ai;
1082 var innerHtml;
1083 attribs = sourceNode.attributes;
1084 ai = attribs.length;
1085 while (ai--) {
1086 attrName = attribs[ai].name;
1087 attrValue = attribs[ai].value;
1088 if (attrName !== 'width' && attrName !== 'height' && attrName !== 'style') {
1089 if (attrName === 'data' || attrName === 'src') {
1090 attrValue = editor.convertURL(attrValue, attrName);
1091 }
1092 targetNode.attr('data-mce-p-' + attrName, attrValue);
1093 }
1094 }
1095 innerHtml = sourceNode.firstChild && sourceNode.firstChild.value;
1096 if (innerHtml) {
1097 targetNode.attr('data-mce-html', escape(Sanitize.sanitize(editor, innerHtml)));
1098 targetNode.firstChild = null;
1099 }
1100 };
1101 var isWithinEphoxEmbed = function (node) {
1102 while (node = node.parent) {
1103 if (node.attr('data-ephox-embed-iri')) {
1104 return true;
1105 }
1106 }
1107 return false;
1108 };
1109 var placeHolderConverter = function (editor) {
1110 return function (nodes) {
1111 var i = nodes.length;
1112 var node;
1113 var videoScript;
1114 while (i--) {
1115 node = nodes[i];
1116 if (!node.parent) {
1117 continue;
1118 }
1119 if (node.parent.attr('data-mce-object')) {
1120 continue;
1121 }
1122 if (node.name === 'script') {
1123 videoScript = VideoScript.getVideoScriptMatch(Settings.getScripts(editor), node.attr('src'));
1124 if (!videoScript) {
1125 continue;
1126 }
1127 }
1128 if (videoScript) {
1129 if (videoScript.width) {
1130 node.attr('width', videoScript.width.toString());
1131 }
1132 if (videoScript.height) {
1133 node.attr('height', videoScript.height.toString());
1134 }
1135 }
1136 if (node.name === 'iframe' && Settings.hasLiveEmbeds(editor) && global$1.ceFalse) {
1137 if (!isWithinEphoxEmbed(node)) {
1138 node.replace(createPreviewIframeNode(editor, node));
1139 }
1140 } else {
1141 if (!isWithinEphoxEmbed(node)) {
1142 node.replace(createPlaceholderNode(editor, node));
1143 }
1144 }
1145 }
1146 };
1147 };
1148 var Nodes = {
1149 createPreviewIframeNode: createPreviewIframeNode,
1150 createPlaceholderNode: createPlaceholderNode,
1151 placeHolderConverter: placeHolderConverter
1152 };
1153
1154 var setup = function (editor) {
1155 editor.on('preInit', function () {
1156 var specialElements = editor.schema.getSpecialElements();
1157 global$2.each('video audio iframe object'.split(' '), function (name) {
1158 specialElements[name] = new RegExp('</' + name + '[^>]*>', 'gi');
1159 });
1160 var boolAttrs = editor.schema.getBoolAttrs();
1161 global$2.each('webkitallowfullscreen mozallowfullscreen allowfullscreen'.split(' '), function (name) {
1162 boolAttrs[name] = {};
1163 });
1164 editor.parser.addNodeFilter('iframe,video,audio,object,embed,script', Nodes.placeHolderConverter(editor));
1165 editor.serializer.addAttributeFilter('data-mce-object', function (nodes, name) {
1166 var i = nodes.length;
1167 var node;
1168 var realElm;
1169 var ai;
1170 var attribs;
1171 var innerHtml;
1172 var innerNode;
1173 var realElmName;
1174 var className;
1175 while (i--) {
1176 node = nodes[i];
1177 if (!node.parent) {
1178 continue;
1179 }
1180 realElmName = node.attr(name);
1181 realElm = new global$8(realElmName, 1);
1182 if (realElmName !== 'audio' && realElmName !== 'script') {
1183 className = node.attr('class');
1184 if (className && className.indexOf('mce-preview-object') !== -1) {
1185 realElm.attr({
1186 width: node.firstChild.attr('width'),
1187 height: node.firstChild.attr('height')
1188 });
1189 } else {
1190 realElm.attr({
1191 width: node.attr('width'),
1192 height: node.attr('height')
1193 });
1194 }
1195 }
1196 realElm.attr({ style: node.attr('style') });
1197 attribs = node.attributes;
1198 ai = attribs.length;
1199 while (ai--) {
1200 var attrName = attribs[ai].name;
1201 if (attrName.indexOf('data-mce-p-') === 0) {
1202 realElm.attr(attrName.substr(11), attribs[ai].value);
1203 }
1204 }
1205 if (realElmName === 'script') {
1206 realElm.attr('type', 'text/javascript');
1207 }
1208 innerHtml = node.attr('data-mce-html');
1209 if (innerHtml) {
1210 innerNode = new global$8('#text', 3);
1211 innerNode.raw = true;
1212 innerNode.value = Sanitize.sanitize(editor, unescape(innerHtml));
1213 realElm.append(innerNode);
1214 }
1215 node.replace(realElm);
1216 }
1217 });
1218 });
1219 editor.on('setContent', function () {
1220 editor.$('span.mce-preview-object').each(function (index, elm) {
1221 var $elm = editor.$(elm);
1222 if ($elm.find('span.mce-shim', elm).length === 0) {
1223 $elm.append('<span class="mce-shim"></span>');
1224 }
1225 });
1226 });
1227 };
1228 var FilterContent = { setup: setup };
1229
1230 var setup$1 = function (editor) {
1231 editor.on('ResolveName', function (e) {
1232 var name;
1233 if (e.target.nodeType === 1 && (name = e.target.getAttribute('data-mce-object'))) {
1234 e.name = name;
1235 }
1236 });
1237 };
1238 var ResolveName = { setup: setup$1 };
1239
1240 var setup$2 = function (editor) {
1241 editor.on('click keyup', function () {
1242 var selectedNode = editor.selection.getNode();
1243 if (selectedNode && editor.dom.hasClass(selectedNode, 'mce-preview-object')) {
1244 if (editor.dom.getAttrib(selectedNode, 'data-mce-selected')) {
1245 selectedNode.setAttribute('data-mce-selected', '2');
1246 }
1247 }
1248 });
1249 editor.on('ObjectSelected', function (e) {
1250 var objectType = e.target.getAttribute('data-mce-object');
1251 if (objectType === 'audio' || objectType === 'script') {
1252 e.preventDefault();
1253 }
1254 });
1255 editor.on('objectResized', function (e) {
1256 var target = e.target;
1257 var html;
1258 if (target.getAttribute('data-mce-object')) {
1259 html = target.getAttribute('data-mce-html');
1260 if (html) {
1261 html = unescape(html);
1262 target.setAttribute('data-mce-html', escape(UpdateHtml.updateHtml(html, {
1263 width: e.width,
1264 height: e.height
1265 })));
1266 }
1267 }
1268 });
1269 };
1270 var Selection = { setup: setup$2 };
1271
1272 var register$1 = function (editor) {
1273 editor.addButton('media', {
1274 tooltip: 'Insert/edit media',
1275 cmd: 'mceMedia',
1276 stateSelector: [
1277 'img[data-mce-object]',
1278 'span[data-mce-object]',
1279 'div[data-ephox-embed-iri]'
1280 ]
1281 });
1282 editor.addMenuItem('media', {
1283 icon: 'media',
1284 text: 'Media',
1285 cmd: 'mceMedia',
1286 context: 'insert',
1287 prependToContext: true
1288 });
1289 };
1290 var Buttons = { register: register$1 };
1291
1292 global.add('media', function (editor) {
1293 Commands.register(editor);
1294 Buttons.register(editor);
1295 ResolveName.setup(editor);
1296 FilterContent.setup(editor);
1297 Selection.setup(editor);
1298 return Api.get(editor);
1299 });
1300 function Plugin () {
1301 }
1302
1303 return Plugin;
1304
1305}());
1306})();
1307