balmet.com

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs

plugin.js (41338B)


      1 (function () {
      2 var 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&amp;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 })();