home *** CD-ROM | disk | FTP | other *** search
/ HTML Examples / WP.iso / wordpress2 / wp-includes / js / tinymce / plugins / media / plugin.js next >
Encoding:
JavaScript  |  2017-05-07  |  46.9 KB  |  1,789 lines

  1. (function () {
  2.  
  3. var defs = {}; // id -> {dependencies, definition, instance (possibly undefined)}
  4.  
  5. // Used when there is no 'main' module.
  6. // The name is probably (hopefully) unique so minification removes for releases.
  7. var register_3795 = function (id) {
  8.   var module = dem(id);
  9.   var fragments = id.split('.');
  10.   var target = Function('return this;')();
  11.   for (var i = 0; i < fragments.length - 1; ++i) {
  12.     if (target[fragments[i]] === undefined)
  13.       target[fragments[i]] = {};
  14.     target = target[fragments[i]];
  15.   }
  16.   target[fragments[fragments.length - 1]] = module;
  17. };
  18.  
  19. var instantiate = function (id) {
  20.   var actual = defs[id];
  21.   var dependencies = actual.deps;
  22.   var definition = actual.defn;
  23.   var len = dependencies.length;
  24.   var instances = new Array(len);
  25.   for (var i = 0; i < len; ++i)
  26.     instances[i] = dem(dependencies[i]);
  27.   var defResult = definition.apply(null, instances);
  28.   if (defResult === undefined)
  29.      throw 'module [' + id + '] returned undefined';
  30.   actual.instance = defResult;
  31. };
  32.  
  33. var def = function (id, dependencies, definition) {
  34.   if (typeof id !== 'string')
  35.     throw 'module id must be a string';
  36.   else if (dependencies === undefined)
  37.     throw 'no dependencies for ' + id;
  38.   else if (definition === undefined)
  39.     throw 'no definition function for ' + id;
  40.   defs[id] = {
  41.     deps: dependencies,
  42.     defn: definition,
  43.     instance: undefined
  44.   };
  45. };
  46.  
  47. var dem = function (id) {
  48.   var actual = defs[id];
  49.   if (actual === undefined)
  50.     throw 'module [' + id + '] was undefined';
  51.   else if (actual.instance === undefined)
  52.     instantiate(id);
  53.   return actual.instance;
  54. };
  55.  
  56. var req = function (ids, callback) {
  57.   var len = ids.length;
  58.   var instances = new Array(len);
  59.   for (var i = 0; i < len; ++i)
  60.     instances.push(dem(ids[i]));
  61.   callback.apply(null, callback);
  62. };
  63.  
  64. var ephox = {};
  65.  
  66. ephox.bolt = {
  67.   module: {
  68.     api: {
  69.       define: def,
  70.       require: req,
  71.       demand: dem
  72.     }
  73.   }
  74. };
  75.  
  76. var define = def;
  77. var require = req;
  78. var demand = dem;
  79. // this helps with minificiation when using a lot of global references
  80. var defineGlobal = function (id, ref) {
  81.   define(id, [], function () { return ref; });
  82. };
  83. /*jsc
  84. ["tinymce.plugins.media.Plugin","tinymce.core.html.Node","tinymce.core.PluginManager","tinymce.core.util.Tools","tinymce.plugins.media.core.Nodes","tinymce.plugins.media.core.Sanitize","tinymce.plugins.media.core.UpdateHtml","tinymce.plugins.media.ui.Dialog","global!tinymce.util.Tools.resolve","tinymce.core.html.Writer","tinymce.core.html.SaxParser","tinymce.core.html.Schema","tinymce.plugins.media.core.VideoScript","tinymce.core.Env","tinymce.core.dom.DOMUtils","tinymce.plugins.media.core.Size","tinymce.core.util.Delay","tinymce.plugins.media.core.HtmlToData","tinymce.plugins.media.core.Service","tinymce.plugins.media.ui.SizeManager","tinymce.plugins.media.core.DataToHtml","tinymce.core.util.Promise","tinymce.plugins.media.core.Mime","tinymce.plugins.media.core.UrlPatterns"]
  85. jsc*/
  86. defineGlobal("global!tinymce.util.Tools.resolve", tinymce.util.Tools.resolve);
  87. /**
  88.  * ResolveGlobal.js
  89.  *
  90.  * Released under LGPL License.
  91.  * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
  92.  *
  93.  * License: http://www.tinymce.com/license
  94.  * Contributing: http://www.tinymce.com/contributing
  95.  */
  96.  
  97. define(
  98.   'tinymce.core.html.Node',
  99.   [
  100.     'global!tinymce.util.Tools.resolve'
  101.   ],
  102.   function (resolve) {
  103.     return resolve('tinymce.html.Node');
  104.   }
  105. );
  106.  
  107. /**
  108.  * ResolveGlobal.js
  109.  *
  110.  * Released under LGPL License.
  111.  * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
  112.  *
  113.  * License: http://www.tinymce.com/license
  114.  * Contributing: http://www.tinymce.com/contributing
  115.  */
  116.  
  117. define(
  118.   'tinymce.core.PluginManager',
  119.   [
  120.     'global!tinymce.util.Tools.resolve'
  121.   ],
  122.   function (resolve) {
  123.     return resolve('tinymce.PluginManager');
  124.   }
  125. );
  126.  
  127. /**
  128.  * ResolveGlobal.js
  129.  *
  130.  * Released under LGPL License.
  131.  * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
  132.  *
  133.  * License: http://www.tinymce.com/license
  134.  * Contributing: http://www.tinymce.com/contributing
  135.  */
  136.  
  137. define(
  138.   'tinymce.core.util.Tools',
  139.   [
  140.     'global!tinymce.util.Tools.resolve'
  141.   ],
  142.   function (resolve) {
  143.     return resolve('tinymce.util.Tools');
  144.   }
  145. );
  146.  
  147. /**
  148.  * ResolveGlobal.js
  149.  *
  150.  * Released under LGPL License.
  151.  * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
  152.  *
  153.  * License: http://www.tinymce.com/license
  154.  * Contributing: http://www.tinymce.com/contributing
  155.  */
  156.  
  157. define(
  158.   'tinymce.core.html.Writer',
  159.   [
  160.     'global!tinymce.util.Tools.resolve'
  161.   ],
  162.   function (resolve) {
  163.     return resolve('tinymce.html.Writer');
  164.   }
  165. );
  166.  
  167. /**
  168.  * ResolveGlobal.js
  169.  *
  170.  * Released under LGPL License.
  171.  * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
  172.  *
  173.  * License: http://www.tinymce.com/license
  174.  * Contributing: http://www.tinymce.com/contributing
  175.  */
  176.  
  177. define(
  178.   'tinymce.core.html.SaxParser',
  179.   [
  180.     'global!tinymce.util.Tools.resolve'
  181.   ],
  182.   function (resolve) {
  183.     return resolve('tinymce.html.SaxParser');
  184.   }
  185. );
  186.  
  187. /**
  188.  * ResolveGlobal.js
  189.  *
  190.  * Released under LGPL License.
  191.  * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
  192.  *
  193.  * License: http://www.tinymce.com/license
  194.  * Contributing: http://www.tinymce.com/contributing
  195.  */
  196.  
  197. define(
  198.   'tinymce.core.html.Schema',
  199.   [
  200.     'global!tinymce.util.Tools.resolve'
  201.   ],
  202.   function (resolve) {
  203.     return resolve('tinymce.html.Schema');
  204.   }
  205. );
  206.  
  207. /**
  208.  * Sanitize.js
  209.  *
  210.  * Released under LGPL License.
  211.  * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
  212.  *
  213.  * License: http://www.tinymce.com/license
  214.  * Contributing: http://www.tinymce.com/contributing
  215.  */
  216.  
  217. define(
  218.   'tinymce.plugins.media.core.Sanitize',
  219.   [
  220.     'tinymce.core.util.Tools',
  221.     'tinymce.core.html.Writer',
  222.     'tinymce.core.html.SaxParser',
  223.     'tinymce.core.html.Schema'
  224.   ],
  225.   function (Tools, Writer, SaxParser, Schema) {
  226.     var sanitize = function (editor, html) {
  227.       if (editor.settings.media_filter_html === false) {
  228.         return html;
  229.       }
  230.  
  231.       var writer = new Writer();
  232.       var blocked;
  233.  
  234.       new SaxParser({
  235.         validate: false,
  236.         allow_conditional_comments: false,
  237.         special: 'script,noscript',
  238.  
  239.         comment: function (text) {
  240.           writer.comment(text);
  241.         },
  242.  
  243.         cdata: function (text) {
  244.           writer.cdata(text);
  245.         },
  246.  
  247.         text: function (text, raw) {
  248.           writer.text(text, raw);
  249.         },
  250.  
  251.         start: function (name, attrs, empty) {
  252.           blocked = true;
  253.  
  254.           if (name === 'script' || name === 'noscript') {
  255.             return;
  256.           }
  257.  
  258.           for (var i = 0; i < attrs.length; i++) {
  259.             if (attrs[i].name.indexOf('on') === 0) {
  260.               return;
  261.             }
  262.  
  263.             if (attrs[i].name === 'style') {
  264.               attrs[i].value = editor.dom.serializeStyle(editor.dom.parseStyle(attrs[i].value), name);
  265.             }
  266.           }
  267.  
  268.           writer.start(name, attrs, empty);
  269.           blocked = false;
  270.         },
  271.  
  272.         end: function (name) {
  273.           if (blocked) {
  274.             return;
  275.           }
  276.  
  277.           writer.end(name);
  278.         }
  279.       }, new Schema({})).parse(html);
  280.  
  281.       return writer.getContent();
  282.     };
  283.  
  284.     return {
  285.       sanitize: sanitize
  286.     };
  287.   }
  288. );
  289. /**
  290.  * VideoScript.js
  291.  *
  292.  * Released under LGPL License.
  293.  * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
  294.  *
  295.  * License: http://www.tinymce.com/license
  296.  * Contributing: http://www.tinymce.com/contributing
  297.  */
  298.  
  299. define(
  300.   'tinymce.plugins.media.core.VideoScript',
  301.   [
  302.   ],
  303.   function () {
  304.     var getVideoScriptMatch = function (prefixes, src) {
  305.       // var prefixes = editor.settings.media_scripts;
  306.       if (prefixes) {
  307.         for (var i = 0; i < prefixes.length; i++) {
  308.           if (src.indexOf(prefixes[i].filter) !== -1) {
  309.             return prefixes[i];
  310.           }
  311.         }
  312.       }
  313.     };
  314.  
  315.     return {
  316.       getVideoScriptMatch: getVideoScriptMatch
  317.     };
  318.   }
  319. );
  320. /**
  321.  * ResolveGlobal.js
  322.  *
  323.  * Released under LGPL License.
  324.  * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
  325.  *
  326.  * License: http://www.tinymce.com/license
  327.  * Contributing: http://www.tinymce.com/contributing
  328.  */
  329.  
  330. define(
  331.   'tinymce.core.Env',
  332.   [
  333.     'global!tinymce.util.Tools.resolve'
  334.   ],
  335.   function (resolve) {
  336.     return resolve('tinymce.Env');
  337.   }
  338. );
  339.  
  340. /**
  341.  * Nodes.js
  342.  *
  343.  * Released under LGPL License.
  344.  * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
  345.  *
  346.  * License: http://www.tinymce.com/license
  347.  * Contributing: http://www.tinymce.com/contributing
  348.  */
  349.  
  350. define(
  351.   'tinymce.plugins.media.core.Nodes',
  352.   [
  353.     'tinymce.plugins.media.core.Sanitize',
  354.     'tinymce.plugins.media.core.VideoScript',
  355.     'tinymce.core.html.Node',
  356.     'tinymce.core.Env'
  357.   ],
  358.   function (Sanitize, VideoScript, Node, Env) {
  359.     var createPlaceholderNode = function (editor, node) {
  360.       var placeHolder;
  361.       var name = node.name;
  362.  
  363.       placeHolder = new Node('img', 1);
  364.       placeHolder.shortEnded = true;
  365.  
  366.       retainAttributesAndInnerHtml(editor, node, placeHolder);
  367.  
  368.       placeHolder.attr({
  369.         width: node.attr('width') || "300",
  370.         height: node.attr('height') || (name === "audio" ? "30" : "150"),
  371.         style: node.attr('style'),
  372.         src: Env.transparentSrc,
  373.         "data-mce-object": name,
  374.         "class": "mce-object mce-object-" + name
  375.       });
  376.  
  377.       return placeHolder;
  378.     };
  379.  
  380.     var createPreviewIframeNode = function (editor, node) {
  381.       var previewWrapper;
  382.       var previewNode;
  383.       var shimNode;
  384.       var name = node.name;
  385.  
  386.       previewWrapper = new Node('span', 1);
  387.       previewWrapper.attr({
  388.         contentEditable: 'false',
  389.         style: node.attr('style'),
  390.         "data-mce-object": name,
  391.         "class": "mce-preview-object mce-object-" + name
  392.       });
  393.  
  394.       retainAttributesAndInnerHtml(editor, node, previewWrapper);
  395.  
  396.       previewNode = new Node(name, 1);
  397.       previewNode.attr({
  398.         src: node.attr('src'),
  399.         allowfullscreen: node.attr('allowfullscreen'),
  400.         width: node.attr('width') || "300",
  401.         height: node.attr('height') || (name === "audio" ? "30" : "150"),
  402.         frameborder: '0'
  403.       });
  404.  
  405.       shimNode = new Node('span', 1);
  406.       shimNode.attr('class', 'mce-shim');
  407.  
  408.       previewWrapper.append(previewNode);
  409.       previewWrapper.append(shimNode);
  410.  
  411.       return previewWrapper;
  412.     };
  413.  
  414.     var retainAttributesAndInnerHtml = function (editor, sourceNode, targetNode) {
  415.       var attrName;
  416.       var attrValue;
  417.       var attribs;
  418.       var ai;
  419.       var innerHtml;
  420.  
  421.       // Prefix all attributes except width, height and style since we
  422.       // will add these to the placeholder
  423.       attribs = sourceNode.attributes;
  424.       ai = attribs.length;
  425.       while (ai--) {
  426.         attrName = attribs[ai].name;
  427.         attrValue = attribs[ai].value;
  428.  
  429.         if (attrName !== "width" && attrName !== "height" && attrName !== "style") {
  430.           if (attrName === "data" || attrName === "src") {
  431.             attrValue = editor.convertURL(attrValue, attrName);
  432.           }
  433.  
  434.           targetNode.attr('data-mce-p-' + attrName, attrValue);
  435.         }
  436.       }
  437.  
  438.       // Place the inner HTML contents inside an escaped attribute
  439.       // This enables us to copy/paste the fake object
  440.       innerHtml = sourceNode.firstChild && sourceNode.firstChild.value;
  441.       if (innerHtml) {
  442.         targetNode.attr("data-mce-html", escape(Sanitize.sanitize(editor, innerHtml)));
  443.         targetNode.firstChild = null;
  444.       }
  445.     };
  446.  
  447.     var isWithinEphoxEmbed = function (node) {
  448.       while ((node = node.parent)) {
  449.         if (node.attr('data-ephox-embed-iri')) {
  450.           return true;
  451.         }
  452.       }
  453.  
  454.       return false;
  455.     };
  456.  
  457.     var placeHolderConverter = function (editor) {
  458.       return function (nodes) {
  459.         var i = nodes.length;
  460.         var node;
  461.         var videoScript;
  462.  
  463.         while (i--) {
  464.           node = nodes[i];
  465.           if (!node.parent) {
  466.             continue;
  467.           }
  468.  
  469.           if (node.parent.attr('data-mce-object')) {
  470.             continue;
  471.           }
  472.  
  473.           if (node.name === 'script') {
  474.             videoScript = VideoScript.getVideoScriptMatch(editor.settings.media_scripts, node.attr('src'));
  475.             if (!videoScript) {
  476.               continue;
  477.             }
  478.           }
  479.  
  480.           if (videoScript) {
  481.             if (videoScript.width) {
  482.               node.attr('width', videoScript.width.toString());
  483.             }
  484.  
  485.             if (videoScript.height) {
  486.               node.attr('height', videoScript.height.toString());
  487.             }
  488.           }
  489.  
  490.           if (node.name === 'iframe' && editor.settings.media_live_embeds !== false && Env.ceFalse) {
  491.             if (!isWithinEphoxEmbed(node)) {
  492.               node.replace(createPreviewIframeNode(editor, node));
  493.             }
  494.           } else {
  495.             if (!isWithinEphoxEmbed(node)) {
  496.               node.replace(createPlaceholderNode(editor, node));
  497.             }
  498.           }
  499.         }
  500.       };
  501.     };
  502.  
  503.     return {
  504.       createPreviewIframeNode: createPreviewIframeNode,
  505.       createPlaceholderNode: createPlaceholderNode,
  506.       placeHolderConverter: placeHolderConverter
  507.     };
  508.   }
  509. );
  510. /**
  511.  * ResolveGlobal.js
  512.  *
  513.  * Released under LGPL License.
  514.  * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
  515.  *
  516.  * License: http://www.tinymce.com/license
  517.  * Contributing: http://www.tinymce.com/contributing
  518.  */
  519.  
  520. define(
  521.   'tinymce.core.dom.DOMUtils',
  522.   [
  523.     'global!tinymce.util.Tools.resolve'
  524.   ],
  525.   function (resolve) {
  526.     return resolve('tinymce.dom.DOMUtils');
  527.   }
  528. );
  529.  
  530. /**
  531.  * Size.js
  532.  *
  533.  * Released under LGPL License.
  534.  * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
  535.  *
  536.  * License: http://www.tinymce.com/license
  537.  * Contributing: http://www.tinymce.com/contributing
  538.  */
  539.  
  540. define(
  541.   'tinymce.plugins.media.core.Size',
  542.   [
  543.   ],
  544.   function () {
  545.     var trimPx = function (value) {
  546.       return value.replace(/px$/, '');
  547.     };
  548.  
  549.     var addPx = function (value) {
  550.       return /^[0-9.]+$/.test(value) ? (value + 'px') : value;
  551.     };
  552.  
  553.     var getSize = function (name) {
  554.       return function (elm) {
  555.         return elm ? trimPx(elm.style[name]) : '';
  556.       };
  557.     };
  558.  
  559.     var setSize = function (name) {
  560.       return function (elm, value) {
  561.         if (elm) {
  562.           elm.style[name] = addPx(value);
  563.         }
  564.       };
  565.     };
  566.  
  567.     return {
  568.       getMaxWidth: getSize('maxWidth'),
  569.       getMaxHeight: getSize('maxHeight'),
  570.       setMaxWidth: setSize('maxWidth'),
  571.       setMaxHeight: setSize('maxHeight')
  572.     };
  573.   }
  574. );
  575. /**
  576.  * UpdateHtml.js
  577.  *
  578.  * Released under LGPL License.
  579.  * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
  580.  *
  581.  * License: http://www.tinymce.com/license
  582.  * Contributing: http://www.tinymce.com/contributing
  583.  */
  584.  
  585. define(
  586.   'tinymce.plugins.media.core.UpdateHtml',
  587.   [
  588.     'tinymce.core.html.Writer',
  589.     'tinymce.core.html.SaxParser',
  590.     'tinymce.core.html.Schema',
  591.     'tinymce.core.dom.DOMUtils',
  592.     'tinymce.plugins.media.core.Size'
  593.   ],
  594.   function (Writer, SaxParser, Schema, DOMUtils, Size) {
  595.     var DOM = DOMUtils.DOM;
  596.  
  597.     var setAttributes = function (attrs, updatedAttrs) {
  598.       var name;
  599.       var i;
  600.       var value;
  601.       var attr;
  602.  
  603.       for (name in updatedAttrs) {
  604.         value = "" + updatedAttrs[name];
  605.  
  606.         if (attrs.map[name]) {
  607.           i = attrs.length;
  608.           while (i--) {
  609.             attr = attrs[i];
  610.  
  611.             if (attr.name === name) {
  612.               if (value) {
  613.                 attrs.map[name] = value;
  614.                 attr.value = value;
  615.               } else {
  616.                 delete attrs.map[name];
  617.                 attrs.splice(i, 1);
  618.               }
  619.             }
  620.           }
  621.         } else if (value) {
  622.           attrs.push({
  623.             name: name,
  624.             value: value
  625.           });
  626.  
  627.           attrs.map[name] = value;
  628.         }
  629.       }
  630.     };
  631.  
  632.     var normalizeHtml = function (html) {
  633.       var writer = new Writer();
  634.       var parser = new SaxParser(writer);
  635.       parser.parse(html);
  636.       return writer.getContent();
  637.     };
  638.  
  639.     var updateHtmlSax = function (html, data, updateAll) {
  640.       var writer = new Writer();
  641.       var sourceCount = 0;
  642.       var hasImage;
  643.  
  644.       new SaxParser({
  645.         validate: false,
  646.         allow_conditional_comments: true,
  647.         special: 'script,noscript',
  648.  
  649.         comment: function (text) {
  650.           writer.comment(text);
  651.         },
  652.  
  653.         cdata: function (text) {
  654.           writer.cdata(text);
  655.         },
  656.  
  657.         text: function (text, raw) {
  658.           writer.text(text, raw);
  659.         },
  660.  
  661.         start: function (name, attrs, empty) {
  662.           switch (name) {
  663.             case "video":
  664.             case "object":
  665.             case "embed":
  666.             case "img":
  667.             case "iframe":
  668.               if (data.height !== undefined && data.width !== undefined) {
  669.                 setAttributes(attrs, {
  670.                   width: data.width,
  671.                   height: data.height
  672.                 });
  673.               }
  674.               break;
  675.           }
  676.  
  677.           if (updateAll) {
  678.             switch (name) {
  679.               case "video":
  680.                 setAttributes(attrs, {
  681.                   poster: data.poster,
  682.                   src: ""
  683.                 });
  684.  
  685.                 if (data.source2) {
  686.                   setAttributes(attrs, {
  687.                     src: ""
  688.                   });
  689.                 }
  690.                 break;
  691.  
  692.               case "iframe":
  693.                 setAttributes(attrs, {
  694.                   src: data.source1
  695.                 });
  696.                 break;
  697.  
  698.               case "source":
  699.                 sourceCount++;
  700.  
  701.                 if (sourceCount <= 2) {
  702.                   setAttributes(attrs, {
  703.                     src: data["source" + sourceCount],
  704.                     type: data["source" + sourceCount + "mime"]
  705.                   });
  706.  
  707.                   if (!data["source" + sourceCount]) {
  708.                     return;
  709.                   }
  710.                 }
  711.                 break;
  712.  
  713.               case "img":
  714.                 if (!data.poster) {
  715.                   return;
  716.                 }
  717.  
  718.                 hasImage = true;
  719.                 break;
  720.             }
  721.           }
  722.  
  723.           writer.start(name, attrs, empty);
  724.         },
  725.  
  726.         end: function (name) {
  727.           if (name === "video" && updateAll) {
  728.             for (var index = 1; index <= 2; index++) {
  729.               if (data["source" + index]) {
  730.                 var attrs = [];
  731.                 attrs.map = {};
  732.  
  733.                 if (sourceCount < index) {
  734.                   setAttributes(attrs, {
  735.                     src: data["source" + index],
  736.                     type: data["source" + index + "mime"]
  737.                   });
  738.  
  739.                   writer.start("source", attrs, true);
  740.                 }
  741.               }
  742.             }
  743.           }
  744.  
  745.           if (data.poster && name === "object" && updateAll && !hasImage) {
  746.             var imgAttrs = [];
  747.             imgAttrs.map = {};
  748.  
  749.             setAttributes(imgAttrs, {
  750.               src: data.poster,
  751.               width: data.width,
  752.               height: data.height
  753.             });
  754.  
  755.             writer.start("img", imgAttrs, true);
  756.           }
  757.  
  758.           writer.end(name);
  759.         }
  760.       }, new Schema({})).parse(html);
  761.  
  762.       return writer.getContent();
  763.     };
  764.  
  765.     var isEphoxEmbed = function (html) {
  766.       var fragment = DOM.createFragment(html);
  767.       return DOM.getAttrib(fragment.firstChild, 'data-ephox-embed-iri') !== '';
  768.     };
  769.  
  770.     var updateEphoxEmbed = function (html, data) {
  771.       var fragment = DOM.createFragment(html);
  772.       var div = fragment.firstChild;
  773.  
  774.       Size.setMaxWidth(div, data.width);
  775.       Size.setMaxHeight(div, data.height);
  776.  
  777.       return normalizeHtml(div.outerHTML);
  778.     };
  779.  
  780.     var updateHtml = function (html, data, updateAll) {
  781.       return isEphoxEmbed(html) ? updateEphoxEmbed(html, data) : updateHtmlSax(html, data, updateAll);
  782.     };
  783.  
  784.     return {
  785.       updateHtml: updateHtml
  786.     };
  787.   }
  788. );
  789. /**
  790.  * ResolveGlobal.js
  791.  *
  792.  * Released under LGPL License.
  793.  * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
  794.  *
  795.  * License: http://www.tinymce.com/license
  796.  * Contributing: http://www.tinymce.com/contributing
  797.  */
  798.  
  799. define(
  800.   'tinymce.core.util.Delay',
  801.   [
  802.     'global!tinymce.util.Tools.resolve'
  803.   ],
  804.   function (resolve) {
  805.     return resolve('tinymce.util.Delay');
  806.   }
  807. );
  808.  
  809. /**
  810.  * HtmlToData.js
  811.  *
  812.  * Released under LGPL License.
  813.  * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
  814.  *
  815.  * License: http://www.tinymce.com/license
  816.  * Contributing: http://www.tinymce.com/contributing
  817.  */
  818.  
  819. define(
  820.   'tinymce.plugins.media.core.HtmlToData',
  821.   [
  822.     'tinymce.core.util.Tools',
  823.     'tinymce.core.html.SaxParser',
  824.     'tinymce.core.html.Schema',
  825.     'tinymce.core.dom.DOMUtils',
  826.     'tinymce.plugins.media.core.VideoScript',
  827.     'tinymce.plugins.media.core.Size'
  828.   ],
  829.   function (Tools, SaxParser, Schema, DOMUtils, VideoScript, Size) {
  830.     var DOM = DOMUtils.DOM;
  831.  
  832.     var getEphoxEmbedIri = function (elm) {
  833.       return DOM.getAttrib(elm, 'data-ephox-embed-iri');
  834.     };
  835.  
  836.     var isEphoxEmbed = function (html) {
  837.       var fragment = DOM.createFragment(html);
  838.       return getEphoxEmbedIri(fragment.firstChild) !== '';
  839.     };
  840.  
  841.     var htmlToDataSax = function (prefixes, html) {
  842.       var data = {};
  843.  
  844.       new SaxParser({
  845.         validate: false,
  846.         allow_conditional_comments: true,
  847.         special: 'script,noscript',
  848.         start: function (name, attrs) {
  849.           if (!data.source1 && name === "param") {
  850.             data.source1 = attrs.map.movie;
  851.           }
  852.  
  853.           if (name === "iframe" || name === "object" || name === "embed" || name === "video" || name === "audio") {
  854.             if (!data.type) {
  855.               data.type = name;
  856.             }
  857.  
  858.             data = Tools.extend(attrs.map, data);
  859.           }
  860.  
  861.           if (name === "script") {
  862.             var videoScript = VideoScript.getVideoScriptMatch(prefixes, attrs.map.src);
  863.             if (!videoScript) {
  864.               return;
  865.             }
  866.  
  867.             data = {
  868.               type: "script",
  869.               source1: attrs.map.src,
  870.               width: videoScript.width,
  871.               height: videoScript.height
  872.             };
  873.           }
  874.  
  875.           if (name === "source") {
  876.             if (!data.source1) {
  877.               data.source1 = attrs.map.src;
  878.             } else if (!data.source2) {
  879.               data.source2 = attrs.map.src;
  880.             }
  881.           }
  882.  
  883.           if (name === "img" && !data.poster) {
  884.             data.poster = attrs.map.src;
  885.           }
  886.         }
  887.       }).parse(html);
  888.  
  889.       data.source1 = data.source1 || data.src || data.data;
  890.       data.source2 = data.source2 || '';
  891.       data.poster = data.poster || '';
  892.  
  893.       return data;
  894.     };
  895.  
  896.     var ephoxEmbedHtmlToData = function (html) {
  897.       var fragment = DOM.createFragment(html);
  898.       var div = fragment.firstChild;
  899.  
  900.       return {
  901.         type: 'ephox-embed-iri',
  902.         source1: getEphoxEmbedIri(div),
  903.         source2: '',
  904.         poster: '',
  905.         width: Size.getMaxWidth(div),
  906.         height: Size.getMaxHeight(div)
  907.       };
  908.     };
  909.  
  910.     var htmlToData = function (prefixes, html) {
  911.       return isEphoxEmbed(html) ? ephoxEmbedHtmlToData(html) : htmlToDataSax(prefixes, html);
  912.     };
  913.  
  914.     return {
  915.       htmlToData: htmlToData
  916.     };
  917.   }
  918. );
  919. /**
  920.  * Mime.js
  921.  *
  922.  * Released under LGPL License.
  923.  * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
  924.  *
  925.  * License: http://www.tinymce.com/license
  926.  * Contributing: http://www.tinymce.com/contributing
  927.  */
  928.  
  929. define(
  930.   'tinymce.plugins.media.core.Mime',
  931.   [
  932.   ],
  933.   function () {
  934.     var guess = function (url) {
  935.       var mimes = {
  936.         'mp3': 'audio/mpeg',
  937.         'wav': 'audio/wav',
  938.         'mp4': 'video/mp4',
  939.         'webm': 'video/webm',
  940.         'ogg': 'video/ogg',
  941.         'swf': 'application/x-shockwave-flash'
  942.       };
  943.       var fileEnd = url.toLowerCase().split('.').pop();
  944.       var mime = mimes[fileEnd];
  945.  
  946.       return mime ? mime : '';
  947.     };
  948.  
  949.     return {
  950.       guess: guess
  951.     };
  952.   }
  953. );
  954. /**
  955.  * UrlPatterns.js
  956.  *
  957.  * Released under LGPL License.
  958.  * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
  959.  *
  960.  * License: http://www.tinymce.com/license
  961.  * Contributing: http://www.tinymce.com/contributing
  962.  */
  963.  
  964. define(
  965.   'tinymce.plugins.media.core.UrlPatterns',
  966.   [
  967.   ],
  968.   function () {
  969.     var urlPatterns = [
  970.       {
  971.         regex: /youtu\.be\/([\w\-.]+)/,
  972.         type: 'iframe', w: 560, h: 314,
  973.         url: '//www.youtube.com/embed/$1',
  974.         allowFullscreen: true
  975.       },
  976.       {
  977.         regex: /youtube\.com(.+)v=([^&]+)/,
  978.         type: 'iframe', w: 560, h: 314,
  979.         url: '//www.youtube.com/embed/$2',
  980.         allowFullscreen: true
  981.       },
  982.       {
  983.         regex: /youtube.com\/embed\/([a-z0-9\-_]+(?:\?.+)?)/i,
  984.         type: 'iframe', w: 560, h: 314,
  985.         url: '//www.youtube.com/embed/$1',
  986.         allowFullscreen: true
  987.       },
  988.       {
  989.         regex: /vimeo\.com\/([0-9]+)/,
  990.         type: 'iframe', w: 425, h: 350,
  991.         url: '//player.vimeo.com/video/$1?title=0&byline=0&portrait=0&color=8dc7dc',
  992.         allowfullscreen: true
  993.       },
  994.       {
  995.         regex: /vimeo\.com\/(.*)\/([0-9]+)/,
  996.         type: "iframe", w: 425, h: 350,
  997.         url: "//player.vimeo.com/video/$2?title=0&byline=0",
  998.         allowfullscreen: true
  999.       },
  1000.       {
  1001.         regex: /maps\.google\.([a-z]{2,3})\/maps\/(.+)msid=(.+)/,
  1002.         type: 'iframe', w: 425, h: 350,
  1003.         url: '//maps.google.com/maps/ms?msid=$2&output=embed"',
  1004.         allowFullscreen: false
  1005.       },
  1006.       {
  1007.         regex: /dailymotion\.com\/video\/([^_]+)/,
  1008.         type: 'iframe', w: 480, h: 270,
  1009.         url: '//www.dailymotion.com/embed/video/$1',
  1010.         allowFullscreen: true
  1011.       }
  1012.     ];
  1013.  
  1014.     return {
  1015.       urlPatterns: urlPatterns
  1016.     };
  1017.   }
  1018. );
  1019. /**
  1020.  * DataToHtml.js
  1021.  *
  1022.  * Released under LGPL License.
  1023.  * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
  1024.  *
  1025.  * License: http://www.tinymce.com/license
  1026.  * Contributing: http://www.tinymce.com/contributing
  1027.  */
  1028.  
  1029. define(
  1030.   'tinymce.plugins.media.core.DataToHtml',
  1031.   [
  1032.     'tinymce.plugins.media.core.Mime',
  1033.     'tinymce.plugins.media.core.HtmlToData',
  1034.     'tinymce.plugins.media.core.UrlPatterns',
  1035.     'tinymce.plugins.media.core.VideoScript',
  1036.     'tinymce.plugins.media.core.UpdateHtml',
  1037.     'tinymce.core.util.Tools'
  1038.   ],
  1039.   function (Mime, HtmlToData, UrlPatterns, VideoScript, UpdateHtml, Tools) {
  1040.     var dataToHtml = function (editor, dataIn) {
  1041.       var html = '';
  1042.       var data = Tools.extend({}, dataIn);
  1043.  
  1044.       if (!data.source1) {
  1045.         Tools.extend(data, HtmlToData.htmlToData(editor.settings.media_scripts, data.embed));
  1046.         if (!data.source1) {
  1047.           return '';
  1048.         }
  1049.       }
  1050.  
  1051.       if (!data.source2) {
  1052.         data.source2 = '';
  1053.       }
  1054.  
  1055.       if (!data.poster) {
  1056.         data.poster = '';
  1057.       }
  1058.  
  1059.       data.source1 = editor.convertURL(data.source1, "source");
  1060.       data.source2 = editor.convertURL(data.source2, "source");
  1061.       data.source1mime = Mime.guess(data.source1);
  1062.       data.source2mime = Mime.guess(data.source2);
  1063.       data.poster = editor.convertURL(data.poster, "poster");
  1064.  
  1065.       Tools.each(UrlPatterns.urlPatterns, function (pattern) {
  1066.         var i;
  1067.         var url;
  1068.  
  1069.         var match = pattern.regex.exec(data.source1);
  1070.  
  1071.         if (match) {
  1072.           url = pattern.url;
  1073.  
  1074.           for (i = 0; match[i]; i++) {
  1075.             /*jshint loopfunc:true*/
  1076.             /*eslint no-loop-func:0 */
  1077.             url = url.replace('$' + i, function () {
  1078.               return match[i];
  1079.             });
  1080.           }
  1081.  
  1082.           data.source1 = url;
  1083.           data.type = pattern.type;
  1084.           data.allowFullscreen = pattern.allowFullscreen;
  1085.           data.width = data.width || pattern.w;
  1086.           data.height = data.height || pattern.h;
  1087.         }
  1088.       });
  1089.  
  1090.       if (data.embed) {
  1091.         html = UpdateHtml.updateHtml(data.embed, data, true);
  1092.       } else {
  1093.         var videoScript = VideoScript.getVideoScriptMatch(editor.settings.media_scripts, data.source1);
  1094.         if (videoScript) {
  1095.           data.type = 'script';
  1096.           data.width = videoScript.width;
  1097.           data.height = videoScript.height;
  1098.         }
  1099.  
  1100.         data.width = data.width || 300;
  1101.         data.height = data.height || 150;
  1102.  
  1103.         Tools.each(data, function (value, key) {
  1104.           data[key] = editor.dom.encode(value);
  1105.         });
  1106.  
  1107.         if (data.type === "iframe") {
  1108.           var allowFullscreen = data.allowFullscreen ? ' allowFullscreen="1"' : '';
  1109.           html +=
  1110.             '<iframe src="' + data.source1 +
  1111.             '" width="' + data.width +
  1112.             '" height="' + data.height +
  1113.             '"' + allowFullscreen + '></iframe>';
  1114.         } else if (data.source1mime === "application/x-shockwave-flash") {
  1115.           html +=
  1116.             '<object data="' + data.source1 +
  1117.             '" width="' + data.width +
  1118.             '" height="' + data.height +
  1119.             '" type="application/x-shockwave-flash">';
  1120.  
  1121.           if (data.poster) {
  1122.             html += '<img src="' + data.poster + '" width="' + data.width + '" height="' + data.height + '" />';
  1123.           }
  1124.  
  1125.           html += '</object>';
  1126.         } else if (data.source1mime.indexOf('audio') !== -1) {
  1127.           if (editor.settings.audio_template_callback) {
  1128.             html = editor.settings.audio_template_callback(data);
  1129.           } else {
  1130.             html += (
  1131.               '<audio controls="controls" src="' + data.source1 + '">' +
  1132.               (
  1133.                 data.source2 ?
  1134.                   '\n<source src="' + data.source2 + '"' +
  1135.                   (data.source2mime ? ' type="' + data.source2mime + '"' : '') +
  1136.                   ' />\n' : '') +
  1137.               '</audio>'
  1138.             );
  1139.           }
  1140.         } else if (data.type === "script") {
  1141.           html += '<script src="' + data.source1 + '"></script>';
  1142.         } else {
  1143.           if (editor.settings.video_template_callback) {
  1144.             html = editor.settings.video_template_callback(data);
  1145.           } else {
  1146.             html = (
  1147.               '<video width="' + data.width +
  1148.               '" height="' + data.height + '"' +
  1149.               (data.poster ? ' poster="' + data.poster + '"' : '') + ' controls="controls">\n' +
  1150.               '<source src="' + data.source1 + '"' +
  1151.               (data.source1mime ? ' type="' + data.source1mime + '"' : '') + ' />\n' +
  1152.               (data.source2 ? '<source src="' + data.source2 + '"' +
  1153.                 (data.source2mime ? ' type="' + data.source2mime + '"' : '') + ' />\n' : '') +
  1154.               '</video>'
  1155.             );
  1156.           }
  1157.         }
  1158.       }
  1159.  
  1160.       return html;
  1161.     };
  1162.  
  1163.     return {
  1164.       dataToHtml: dataToHtml
  1165.     };
  1166.   }
  1167. );
  1168. /**
  1169.  * ResolveGlobal.js
  1170.  *
  1171.  * Released under LGPL License.
  1172.  * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
  1173.  *
  1174.  * License: http://www.tinymce.com/license
  1175.  * Contributing: http://www.tinymce.com/contributing
  1176.  */
  1177.  
  1178. define(
  1179.   'tinymce.core.util.Promise',
  1180.   [
  1181.     'global!tinymce.util.Tools.resolve'
  1182.   ],
  1183.   function (resolve) {
  1184.     return resolve('tinymce.util.Promise');
  1185.   }
  1186. );
  1187.  
  1188. /**
  1189.  * Service.js
  1190.  *
  1191.  * Released under LGPL License.
  1192.  * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
  1193.  *
  1194.  * License: http://www.tinymce.com/license
  1195.  * Contributing: http://www.tinymce.com/contributing
  1196.  */
  1197.  
  1198. define(
  1199.   'tinymce.plugins.media.core.Service',
  1200.   [
  1201.     'tinymce.plugins.media.core.DataToHtml',
  1202.     'tinymce.core.util.Promise'
  1203.   ],
  1204.   function (DataToHtml, Promise) {
  1205.     var embedPromise = function (data, dataToHtml, handler) {
  1206.       var cache = {};
  1207.       return new Promise(function (res, rej) {
  1208.         var wrappedResolve = function (response) {
  1209.           if (response.html) {
  1210.             cache[data.source1] = response;
  1211.           }
  1212.           return res({
  1213.             url: data.source1,
  1214.             html: response.html ? response.html : dataToHtml(data)
  1215.           });
  1216.         };
  1217.         if (cache[data.source1]) {
  1218.           wrappedResolve(cache[data.source1]);
  1219.         } else {
  1220.           handler({ url: data.source1 }, wrappedResolve, rej);
  1221.         }
  1222.       });
  1223.     };
  1224.  
  1225.     var defaultPromise = function (data, dataToHtml) {
  1226.       return new Promise(function (res) {
  1227.         res({ html: dataToHtml(data), url: data.source1 });
  1228.       });
  1229.     };
  1230.  
  1231.     var loadedData = function (editor) {
  1232.       return function (data) {
  1233.         return DataToHtml.dataToHtml(editor, data);
  1234.       };
  1235.     };
  1236.  
  1237.     var getEmbedHtml = function (editor, data) {
  1238.       var embedHandler = editor.settings.media_url_resolver;
  1239.  
  1240.       return embedHandler ? embedPromise(data, loadedData(editor), embedHandler) : defaultPromise(data, loadedData(editor));
  1241.     };
  1242.  
  1243.     return {
  1244.       getEmbedHtml: getEmbedHtml
  1245.     };
  1246.   }
  1247. );
  1248. /**
  1249.  * SizeManager.js
  1250.  *
  1251.  * Released under LGPL License.
  1252.  * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
  1253.  *
  1254.  * License: http://www.tinymce.com/license
  1255.  * Contributing: http://www.tinymce.com/contributing
  1256.  */
  1257.  
  1258. define(
  1259.   'tinymce.plugins.media.ui.SizeManager',
  1260.   [
  1261.   ],
  1262.   function () {
  1263.     var doSyncSize = function (widthCtrl, heightCtrl) {
  1264.       widthCtrl.state.set('oldVal', widthCtrl.value());
  1265.       heightCtrl.state.set('oldVal', heightCtrl.value());
  1266.     };
  1267.     var doSizeControls = function (win, f) {
  1268.       var widthCtrl = win.find('#width')[0];
  1269.       var heightCtrl = win.find('#height')[0];
  1270.       var constrained = win.find('#constrain')[0];
  1271.       if (widthCtrl && heightCtrl && constrained) {
  1272.         f(widthCtrl, heightCtrl, constrained.checked());
  1273.       }
  1274.     };
  1275.  
  1276.     var doUpdateSize = function (widthCtrl, heightCtrl, isContrained) {
  1277.       var oldWidth = widthCtrl.state.get('oldVal');
  1278.       var oldHeight = heightCtrl.state.get('oldVal');
  1279.       var newWidth = widthCtrl.value();
  1280.       var newHeight = heightCtrl.value();
  1281.  
  1282.       if (isContrained && oldWidth && oldHeight && newWidth && newHeight) {
  1283.         if (newWidth !== oldWidth) {
  1284.           newHeight = Math.round((newWidth / oldWidth) * newHeight);
  1285.  
  1286.           if (!isNaN(newHeight)) {
  1287.             heightCtrl.value(newHeight);
  1288.           }
  1289.         } else {
  1290.           newWidth = Math.round((newHeight / oldHeight) * newWidth);
  1291.  
  1292.           if (!isNaN(newWidth)) {
  1293.             widthCtrl.value(newWidth);
  1294.           }
  1295.         }
  1296.       }
  1297.  
  1298.       doSyncSize(widthCtrl, heightCtrl);
  1299.     };
  1300.  
  1301.     var syncSize = function (win) {
  1302.       doSizeControls(win, doSyncSize);
  1303.     };
  1304.  
  1305.     var updateSize = function (win) {
  1306.       doSizeControls(win, doUpdateSize);
  1307.     };
  1308.  
  1309.     var createUi = function (onChange) {
  1310.       var recalcSize = function () {
  1311.         onChange(function (win) {
  1312.           updateSize(win);
  1313.         });
  1314.       };
  1315.  
  1316.       return {
  1317.         type: 'container',
  1318.         label: 'Dimensions',
  1319.         layout: 'flex',
  1320.         align: 'center',
  1321.         spacing: 5,
  1322.         items: [
  1323.           {
  1324.             name: 'width', type: 'textbox', maxLength: 5, size: 5,
  1325.             onchange: recalcSize, ariaLabel: 'Width'
  1326.           },
  1327.           { type: 'label', text: 'x' },
  1328.           {
  1329.             name: 'height', type: 'textbox', maxLength: 5, size: 5,
  1330.             onchange: recalcSize, ariaLabel: 'Height'
  1331.           },
  1332.           { name: 'constrain', type: 'checkbox', checked: true, text: 'Constrain proportions' }
  1333.         ]
  1334.       };
  1335.     };
  1336.  
  1337.     return {
  1338.       createUi: createUi,
  1339.       syncSize: syncSize,
  1340.       updateSize: updateSize
  1341.     };
  1342.   }
  1343. );
  1344. /**
  1345.  * Dialog.js
  1346.  *
  1347.  * Released under LGPL License.
  1348.  * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
  1349.  *
  1350.  * License: http://www.tinymce.com/license
  1351.  * Contributing: http://www.tinymce.com/contributing
  1352.  */
  1353.  
  1354. define(
  1355.   'tinymce.plugins.media.ui.Dialog',
  1356.   [
  1357.     'tinymce.core.util.Delay',
  1358.     'tinymce.plugins.media.core.HtmlToData',
  1359.     'tinymce.plugins.media.core.UpdateHtml',
  1360.     'tinymce.plugins.media.core.Service',
  1361.     'tinymce.plugins.media.core.Size',
  1362.     'tinymce.core.util.Tools',
  1363.     'tinymce.core.Env',
  1364.     'tinymce.plugins.media.ui.SizeManager'
  1365.   ],
  1366.   function (Delay, HtmlToData, UpdateHtml, Service, Size, Tools, Env, SizeManager) {
  1367.     var embedChange = (Env.ie && Env.ie <= 8) ? 'onChange' : 'onInput';
  1368.  
  1369.     var handleError = function (editor) {
  1370.       return function (error) {
  1371.         var errorMessage = error && error.msg ?
  1372.           'Media embed handler error: ' + error.msg :
  1373.           'Media embed handler threw unknown error.';
  1374.         editor.notificationManager.open({ type: 'error', text: errorMessage });
  1375.       };
  1376.     };
  1377.  
  1378.     var getData = function (editor) {
  1379.       var element = editor.selection.getNode();
  1380.       var dataEmbed = element.getAttribute('data-ephox-embed-iri');
  1381.  
  1382.       if (dataEmbed) {
  1383.         return {
  1384.           source1: dataEmbed,
  1385.           'data-ephox-embed-iri': dataEmbed,
  1386.           width: Size.getMaxWidth(element),
  1387.           height: Size.getMaxHeight(element)
  1388.         };
  1389.       }
  1390.  
  1391.       return element.getAttribute('data-mce-object') ?
  1392.         HtmlToData.htmlToData(editor.settings.media_scripts, editor.serializer.serialize(element, { selection: true })) :
  1393.         {};
  1394.     };
  1395.  
  1396.     var getSource = function (editor) {
  1397.       var elm = editor.selection.getNode();
  1398.  
  1399.       if (elm.getAttribute('data-mce-object') || elm.getAttribute('data-ephox-embed-iri')) {
  1400.         return editor.selection.getContent();
  1401.       }
  1402.     };
  1403.  
  1404.     var addEmbedHtml = function (win, editor) {
  1405.       return function (response) {
  1406.         var html = response.html;
  1407.         var embed = win.find('#embed')[0];
  1408.         var data = Tools.extend(HtmlToData.htmlToData(editor.settings.media_scripts, html), { source1: response.url });
  1409.         win.fromJSON(data);
  1410.  
  1411.         if (embed) {
  1412.           embed.value(html);
  1413.           SizeManager.updateSize(win);
  1414.         }
  1415.       };
  1416.     };
  1417.  
  1418.     var selectPlaceholder = function (editor, beforeObjects) {
  1419.       var i;
  1420.       var y;
  1421.       var afterObjects = editor.dom.select('img[data-mce-object]');
  1422.  
  1423.       // Find new image placeholder so we can select it
  1424.       for (i = 0; i < beforeObjects.length; i++) {
  1425.         for (y = afterObjects.length - 1; y >= 0; y--) {
  1426.           if (beforeObjects[i] === afterObjects[y]) {
  1427.             afterObjects.splice(y, 1);
  1428.           }
  1429.         }
  1430.       }
  1431.  
  1432.       editor.selection.select(afterObjects[0]);
  1433.     };
  1434.  
  1435.     var handleInsert = function (editor, html) {
  1436.       var beforeObjects = editor.dom.select('img[data-mce-object]');
  1437.  
  1438.       editor.insertContent(html);
  1439.       selectPlaceholder(editor, beforeObjects);
  1440.       editor.nodeChanged();
  1441.     };
  1442.  
  1443.     var submitForm = function (win, editor) {
  1444.       var data = win.toJSON();
  1445.  
  1446.       data.embed = UpdateHtml.updateHtml(data.embed, data);
  1447.  
  1448.       if (data.embed) {
  1449.         handleInsert(editor, data.embed);
  1450.       } else {
  1451.         Service.getEmbedHtml(editor, data)
  1452.           .then(function (response) {
  1453.             handleInsert(editor, response.html);
  1454.           })["catch"](handleError(editor));
  1455.       }
  1456.     };
  1457.  
  1458.     var populateMeta = function (win, meta) {
  1459.       Tools.each(meta, function (value, key) {
  1460.         win.find('#' + key).value(value);
  1461.       });
  1462.     };
  1463.  
  1464.     var showDialog = function (editor) {
  1465.       var win;
  1466.       var data;
  1467.  
  1468.       var generalFormItems = [
  1469.         {
  1470.           name: 'source1',
  1471.           type: 'filepicker',
  1472.           filetype: 'media',
  1473.           size: 40,
  1474.           autofocus: true,
  1475.           label: 'Source',
  1476.           onpaste: function () {
  1477.             setTimeout(function () {
  1478.               Service.getEmbedHtml(editor, win.toJSON())
  1479.                 .then(
  1480.                 addEmbedHtml(win, editor)
  1481.                 )["catch"](handleError(editor));
  1482.             }, 1);
  1483.           },
  1484.           onchange: function (e) {
  1485.             Service.getEmbedHtml(editor, win.toJSON())
  1486.               .then(
  1487.               addEmbedHtml(win, editor)
  1488.               )["catch"](handleError(editor));
  1489.  
  1490.             populateMeta(win, e.meta);
  1491.           },
  1492.           onbeforecall: function (e) {
  1493.             e.meta = win.toJSON();
  1494.           }
  1495.         }
  1496.       ];
  1497.  
  1498.       var advancedFormItems = [];
  1499.  
  1500.       var reserialise = function (update) {
  1501.         update(win);
  1502.         data = win.toJSON();
  1503.         win.find('#embed').value(UpdateHtml.updateHtml(data.embed, data));
  1504.       };
  1505.  
  1506.       if (editor.settings.media_alt_source !== false) {
  1507.         advancedFormItems.push({ name: 'source2', type: 'filepicker', filetype: 'media', size: 40, label: 'Alternative source' });
  1508.       }
  1509.  
  1510.       if (editor.settings.media_poster !== false) {
  1511.         advancedFormItems.push({ name: 'poster', type: 'filepicker', filetype: 'image', size: 40, label: 'Poster' });
  1512.       }
  1513.  
  1514.       if (editor.settings.media_dimensions !== false) {
  1515.         var control = SizeManager.createUi(reserialise);
  1516.         generalFormItems.push(control);
  1517.       }
  1518.  
  1519.       data = getData(editor);
  1520.  
  1521.       var embedTextBox = {
  1522.         id: 'mcemediasource',
  1523.         type: 'textbox',
  1524.         flex: 1,
  1525.         name: 'embed',
  1526.         value: getSource(editor),
  1527.         multiline: true,
  1528.         rows: 5,
  1529.         label: 'Source'
  1530.       };
  1531.  
  1532.       var updateValueOnChange = function () {
  1533.         data = Tools.extend({}, HtmlToData.htmlToData(editor.settings.media_scripts, this.value()));
  1534.         this.parent().parent().fromJSON(data);
  1535.       };
  1536.  
  1537.       embedTextBox[embedChange] = updateValueOnChange;
  1538.  
  1539.       win = editor.windowManager.open({
  1540.         title: 'Insert/edit media',
  1541.         data: data,
  1542.         bodyType: 'tabpanel',
  1543.         body: [
  1544.           {
  1545.             title: 'General',
  1546.             type: "form",
  1547.             items: generalFormItems
  1548.           },
  1549.  
  1550.           {
  1551.             title: 'Embed',
  1552.             type: "container",
  1553.             layout: 'flex',
  1554.             direction: 'column',
  1555.             align: 'stretch',
  1556.             padding: 10,
  1557.             spacing: 10,
  1558.             items: [
  1559.               {
  1560.                 type: 'label',
  1561.                 text: 'Paste your embed code below:',
  1562.                 forId: 'mcemediasource'
  1563.               },
  1564.               embedTextBox
  1565.             ]
  1566.           },
  1567.  
  1568.           {
  1569.             title: 'Advanced',
  1570.             type: "form",
  1571.             items: advancedFormItems
  1572.           }
  1573.         ],
  1574.         onSubmit: function () {
  1575.           SizeManager.updateSize(win);
  1576.           submitForm(win, editor);
  1577.         }
  1578.       });
  1579.  
  1580.       SizeManager.syncSize(win);
  1581.     };
  1582.  
  1583.     return {
  1584.       showDialog: showDialog
  1585.     };
  1586.   }
  1587. );
  1588. /**
  1589.  * Plugin.js
  1590.  *
  1591.  * Released under LGPL License.
  1592.  * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
  1593.  *
  1594.  * License: http://www.tinymce.com/license
  1595.  * Contributing: http://www.tinymce.com/contributing
  1596.  */
  1597.  
  1598. define(
  1599.   'tinymce.plugins.media.Plugin',
  1600.   [
  1601.     'tinymce.core.html.Node',
  1602.     'tinymce.core.PluginManager',
  1603.     'tinymce.core.util.Tools',
  1604.     'tinymce.plugins.media.core.Nodes',
  1605.     'tinymce.plugins.media.core.Sanitize',
  1606.     'tinymce.plugins.media.core.UpdateHtml',
  1607.     'tinymce.plugins.media.ui.Dialog'
  1608.   ],
  1609.   function (Node, PluginManager, Tools, Nodes, Sanitize, UpdateHtml, Dialog) {
  1610.     var Plugin = function (editor) {
  1611.       editor.on('ResolveName', function (e) {
  1612.         var name;
  1613.  
  1614.         if (e.target.nodeType === 1 && (name = e.target.getAttribute("data-mce-object"))) {
  1615.           e.name = name;
  1616.         }
  1617.       });
  1618.  
  1619.       editor.on('preInit', function () {
  1620.         // Make sure that any messy HTML is retained inside these
  1621.         var specialElements = editor.schema.getSpecialElements();
  1622.         Tools.each('video audio iframe object'.split(' '), function (name) {
  1623.           specialElements[name] = new RegExp('<\/' + name + '[^>]*>', 'gi');
  1624.         });
  1625.  
  1626.         // Allow elements
  1627.         //editor.schema.addValidElements(
  1628.         //  'object[id|style|width|height|classid|codebase|*],embed[id|style|width|height|type|src|*],video[*],audio[*]'
  1629.         //);
  1630.  
  1631.         // Set allowFullscreen attribs as boolean
  1632.         var boolAttrs = editor.schema.getBoolAttrs();
  1633.         Tools.each('webkitallowfullscreen mozallowfullscreen allowfullscreen'.split(' '), function (name) {
  1634.           boolAttrs[name] = {};
  1635.         });
  1636.  
  1637.         // Converts iframe, video etc into placeholder images
  1638.         editor.parser.addNodeFilter('iframe,video,audio,object,embed,script',
  1639.           Nodes.placeHolderConverter(editor));
  1640.  
  1641.         // Replaces placeholder images with real elements for video, object, iframe etc
  1642.         editor.serializer.addAttributeFilter('data-mce-object', function (nodes, name) {
  1643.           var i = nodes.length;
  1644.           var node;
  1645.           var realElm;
  1646.           var ai;
  1647.           var attribs;
  1648.           var innerHtml;
  1649.           var innerNode;
  1650.           var realElmName;
  1651.           var className;
  1652.  
  1653.           while (i--) {
  1654.             node = nodes[i];
  1655.             if (!node.parent) {
  1656.               continue;
  1657.             }
  1658.  
  1659.             realElmName = node.attr(name);
  1660.             realElm = new Node(realElmName, 1);
  1661.  
  1662.             // Add width/height to everything but audio
  1663.             if (realElmName !== "audio" && realElmName !== "script") {
  1664.               className = node.attr('class');
  1665.               if (className && className.indexOf('mce-preview-object') !== -1) {
  1666.                 realElm.attr({
  1667.                   width: node.firstChild.attr('width'),
  1668.                   height: node.firstChild.attr('height')
  1669.                 });
  1670.               } else {
  1671.                 realElm.attr({
  1672.                   width: node.attr('width'),
  1673.                   height: node.attr('height')
  1674.                 });
  1675.               }
  1676.             }
  1677.  
  1678.             realElm.attr({
  1679.               style: node.attr('style')
  1680.             });
  1681.  
  1682.             // Unprefix all placeholder attributes
  1683.             attribs = node.attributes;
  1684.             ai = attribs.length;
  1685.             while (ai--) {
  1686.               var attrName = attribs[ai].name;
  1687.  
  1688.               if (attrName.indexOf('data-mce-p-') === 0) {
  1689.                 realElm.attr(attrName.substr(11), attribs[ai].value);
  1690.               }
  1691.             }
  1692.  
  1693.             if (realElmName === "script") {
  1694.               realElm.attr('type', 'text/javascript');
  1695.             }
  1696.  
  1697.             // Inject innerhtml
  1698.             innerHtml = node.attr('data-mce-html');
  1699.             if (innerHtml) {
  1700.               innerNode = new Node('#text', 3);
  1701.               innerNode.raw = true;
  1702.               innerNode.value = Sanitize.sanitize(editor, unescape(innerHtml));
  1703.               realElm.append(innerNode);
  1704.             }
  1705.  
  1706.             node.replace(realElm);
  1707.           }
  1708.         });
  1709.       });
  1710.  
  1711.       editor.on('click keyup', function () {
  1712.         var selectedNode = editor.selection.getNode();
  1713.  
  1714.         if (selectedNode && editor.dom.hasClass(selectedNode, 'mce-preview-object')) {
  1715.           if (editor.dom.getAttrib(selectedNode, 'data-mce-selected')) {
  1716.             selectedNode.setAttribute('data-mce-selected', '2');
  1717.           }
  1718.         }
  1719.       });
  1720.  
  1721.       editor.on('ObjectSelected', function (e) {
  1722.         var objectType = e.target.getAttribute('data-mce-object');
  1723.  
  1724.         if (objectType === "audio" || objectType === "script") {
  1725.           e.preventDefault();
  1726.         }
  1727.       });
  1728.  
  1729.       editor.on('objectResized', function (e) {
  1730.         var target = e.target;
  1731.         var html;
  1732.  
  1733.         if (target.getAttribute('data-mce-object')) {
  1734.           html = target.getAttribute('data-mce-html');
  1735.           if (html) {
  1736.             html = unescape(html);
  1737.             target.setAttribute('data-mce-html', escape(
  1738.               UpdateHtml.updateHtml(html, {
  1739.                 width: e.width,
  1740.                 height: e.height
  1741.               })
  1742.             ));
  1743.           }
  1744.         }
  1745.       });
  1746.  
  1747.       this.showDialog = function () {
  1748.         Dialog.showDialog(editor);
  1749.       };
  1750.  
  1751.       editor.addButton('media', {
  1752.         tooltip: 'Insert/edit media',
  1753.         onclick: this.showDialog,
  1754.         stateSelector: ['img[data-mce-object]', 'span[data-mce-object]', 'div[data-ephox-embed-iri]']
  1755.       });
  1756.  
  1757.       editor.addMenuItem('media', {
  1758.         icon: 'media',
  1759.         text: 'Media',
  1760.         onclick: this.showDialog,
  1761.         context: 'insert',
  1762.         prependToContext: true
  1763.       });
  1764.  
  1765.       editor.on('setContent', function () {
  1766.         // TODO: This shouldn't be needed there should be a way to mark bogus
  1767.         // elements so they are never removed except external save
  1768.         editor.$('span.mce-preview-object').each(function (index, elm) {
  1769.           var $elm = editor.$(elm);
  1770.  
  1771.           if ($elm.find('span.mce-shim', elm).length === 0) {
  1772.             $elm.append('<span class="mce-shim"></span>');
  1773.           }
  1774.         });
  1775.       });
  1776.  
  1777.       editor.addCommand('mceMedia', this.showDialog);
  1778.     };
  1779.  
  1780.     PluginManager.add('media', Plugin);
  1781.  
  1782.     return function () { };
  1783.   }
  1784. );
  1785.  
  1786.  
  1787. dem('tinymce.plugins.media.Plugin')();
  1788. })();
  1789.