home *** CD-ROM | disk | FTP | other *** search
/ HTML Examples / WP.iso / wordpress2 / wp-includes / js / tinymce / plugins / image / plugin.js next >
Encoding:
JavaScript  |  2017-09-26  |  32.5 KB  |  1,160 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.image.Plugin","tinymce.core.PluginManager","tinymce.core.util.Tools","tinymce.plugins.image.ui.Dialog","global!tinymce.util.Tools.resolve","global!document","global!Math","global!RegExp","tinymce.core.Env","tinymce.core.ui.Factory","tinymce.core.util.JSON","tinymce.core.util.XHR","tinymce.plugins.image.core.Uploader","tinymce.plugins.image.core.Utils","tinymce.core.util.Promise"]
  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.PluginManager',
  99.   [
  100.     'global!tinymce.util.Tools.resolve'
  101.   ],
  102.   function (resolve) {
  103.     return resolve('tinymce.PluginManager');
  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.util.Tools',
  119.   [
  120.     'global!tinymce.util.Tools.resolve'
  121.   ],
  122.   function (resolve) {
  123.     return resolve('tinymce.util.Tools');
  124.   }
  125. );
  126.  
  127. defineGlobal("global!document", document);
  128. defineGlobal("global!Math", Math);
  129. defineGlobal("global!RegExp", RegExp);
  130. /**
  131.  * ResolveGlobal.js
  132.  *
  133.  * Released under LGPL License.
  134.  * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
  135.  *
  136.  * License: http://www.tinymce.com/license
  137.  * Contributing: http://www.tinymce.com/contributing
  138.  */
  139.  
  140. define(
  141.   'tinymce.core.Env',
  142.   [
  143.     'global!tinymce.util.Tools.resolve'
  144.   ],
  145.   function (resolve) {
  146.     return resolve('tinymce.Env');
  147.   }
  148. );
  149.  
  150. /**
  151.  * ResolveGlobal.js
  152.  *
  153.  * Released under LGPL License.
  154.  * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
  155.  *
  156.  * License: http://www.tinymce.com/license
  157.  * Contributing: http://www.tinymce.com/contributing
  158.  */
  159.  
  160. define(
  161.   'tinymce.core.ui.Factory',
  162.   [
  163.     'global!tinymce.util.Tools.resolve'
  164.   ],
  165.   function (resolve) {
  166.     return resolve('tinymce.ui.Factory');
  167.   }
  168. );
  169.  
  170. /**
  171.  * ResolveGlobal.js
  172.  *
  173.  * Released under LGPL License.
  174.  * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
  175.  *
  176.  * License: http://www.tinymce.com/license
  177.  * Contributing: http://www.tinymce.com/contributing
  178.  */
  179.  
  180. define(
  181.   'tinymce.core.util.JSON',
  182.   [
  183.     'global!tinymce.util.Tools.resolve'
  184.   ],
  185.   function (resolve) {
  186.     return resolve('tinymce.util.JSON');
  187.   }
  188. );
  189.  
  190. /**
  191.  * ResolveGlobal.js
  192.  *
  193.  * Released under LGPL License.
  194.  * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
  195.  *
  196.  * License: http://www.tinymce.com/license
  197.  * Contributing: http://www.tinymce.com/contributing
  198.  */
  199.  
  200. define(
  201.   'tinymce.core.util.XHR',
  202.   [
  203.     'global!tinymce.util.Tools.resolve'
  204.   ],
  205.   function (resolve) {
  206.     return resolve('tinymce.util.XHR');
  207.   }
  208. );
  209.  
  210. /**
  211.  * ResolveGlobal.js
  212.  *
  213.  * Released under LGPL License.
  214.  * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
  215.  *
  216.  * License: http://www.tinymce.com/license
  217.  * Contributing: http://www.tinymce.com/contributing
  218.  */
  219.  
  220. define(
  221.   'tinymce.core.util.Promise',
  222.   [
  223.     'global!tinymce.util.Tools.resolve'
  224.   ],
  225.   function (resolve) {
  226.     return resolve('tinymce.util.Promise');
  227.   }
  228. );
  229.  
  230. /**
  231.  * Uploader.js
  232.  *
  233.  * Released under LGPL License.
  234.  * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
  235.  *
  236.  * License: http://www.tinymce.com/license
  237.  * Contributing: http://www.tinymce.com/contributing
  238.  */
  239.  
  240. /**
  241.  * This is basically cut down version of tinymce.core.file.Uploader, which we could use directly
  242.  * if it wasn't marked as private.
  243.  *
  244.  * @class tinymce.image.core.Uploader
  245.  * @private
  246.  */
  247. define(
  248.   'tinymce.plugins.image.core.Uploader',
  249.   [
  250.     'tinymce.core.util.Promise',
  251.     'tinymce.core.util.Tools',
  252.     'global!document'
  253.   ],
  254.   function (Promise, Tools, document) {
  255.     return function (settings) {
  256.       var noop = function () {};
  257.  
  258.       function pathJoin(path1, path2) {
  259.         if (path1) {
  260.           return path1.replace(/\/$/, '') + '/' + path2.replace(/^\//, '');
  261.         }
  262.  
  263.         return path2;
  264.       }
  265.  
  266.       function defaultHandler(blobInfo, success, failure, progress) {
  267.         var xhr, formData;
  268.  
  269.         xhr = new XMLHttpRequest();
  270.         xhr.open('POST', settings.url);
  271.         xhr.withCredentials = settings.credentials;
  272.  
  273.         xhr.upload.onprogress = function (e) {
  274.           progress(e.loaded / e.total * 100);
  275.         };
  276.  
  277.         xhr.onerror = function () {
  278.           failure("Image upload failed due to a XHR Transport error. Code: " + xhr.status);
  279.         };
  280.  
  281.         xhr.onload = function () {
  282.           var json;
  283.  
  284.           if (xhr.status < 200 || xhr.status >= 300) {
  285.             failure("HTTP Error: " + xhr.status);
  286.             return;
  287.           }
  288.  
  289.           json = JSON.parse(xhr.responseText);
  290.  
  291.           if (!json || typeof json.location != "string") {
  292.             failure("Invalid JSON: " + xhr.responseText);
  293.             return;
  294.           }
  295.  
  296.           success(pathJoin(settings.basePath, json.location));
  297.         };
  298.  
  299.         formData = new FormData();
  300.         formData.append('file', blobInfo.blob(), blobInfo.filename());
  301.  
  302.         xhr.send(formData);
  303.       }
  304.  
  305.       function uploadBlob(blobInfo, handler) {
  306.         return new Promise(function (resolve, reject) {
  307.           try {
  308.             handler(blobInfo, resolve, reject, noop);
  309.           } catch (ex) {
  310.             reject(ex.message);
  311.           }
  312.         });
  313.       }
  314.  
  315.       function isDefaultHandler(handler) {
  316.         return handler === defaultHandler;
  317.       }
  318.  
  319.       function upload(blobInfo) {
  320.         return (!settings.url && isDefaultHandler(settings.handler)) ? Promise.reject("Upload url missng from the settings.") : uploadBlob(blobInfo, settings.handler);
  321.       }
  322.  
  323.       settings = Tools.extend({
  324.         credentials: false,
  325.         handler: defaultHandler
  326.       }, settings);
  327.  
  328.       return {
  329.         upload: upload
  330.       };
  331.     };
  332.   }
  333. );
  334. /**
  335.  * Utils.js
  336.  *
  337.  * Released under LGPL License.
  338.  * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
  339.  *
  340.  * License: http://www.tinymce.com/license
  341.  * Contributing: http://www.tinymce.com/contributing
  342.  */
  343.  
  344. /**
  345.  * @class tinymce.image.core.Utils
  346.  * @private
  347.  */
  348. define(
  349.   'tinymce.plugins.image.core.Utils',
  350.   [
  351.     'tinymce.core.util.Tools',
  352.     'global!Math',
  353.     'global!document'
  354.   ],
  355.   function (Tools, Math, document) {
  356.  
  357.     var getImageSize = function (url, callback) {
  358.       var img = document.createElement('img');
  359.  
  360.       function done(width, height) {
  361.         if (img.parentNode) {
  362.           img.parentNode.removeChild(img);
  363.         }
  364.  
  365.         callback({ width: width, height: height });
  366.       }
  367.  
  368.       img.onload = function () {
  369.         done(Math.max(img.width, img.clientWidth), Math.max(img.height, img.clientHeight));
  370.       };
  371.  
  372.       img.onerror = function () {
  373.         done();
  374.       };
  375.  
  376.       var style = img.style;
  377.       style.visibility = 'hidden';
  378.       style.position = 'fixed';
  379.       style.bottom = style.left = 0;
  380.       style.width = style.height = 'auto';
  381.  
  382.       document.body.appendChild(img);
  383.       img.src = url;
  384.     };
  385.  
  386.  
  387.     var buildListItems = function (inputList, itemCallback, startItems) {
  388.       function appendItems(values, output) {
  389.         output = output || [];
  390.  
  391.         Tools.each(values, function (item) {
  392.           var menuItem = { text: item.text || item.title };
  393.  
  394.           if (item.menu) {
  395.             menuItem.menu = appendItems(item.menu);
  396.           } else {
  397.             menuItem.value = item.value;
  398.             itemCallback(menuItem);
  399.           }
  400.  
  401.           output.push(menuItem);
  402.         });
  403.  
  404.         return output;
  405.       }
  406.  
  407.       return appendItems(inputList, startItems || []);
  408.     };
  409.  
  410.     var removePixelSuffix = function (value) {
  411.       if (value) {
  412.         value = value.replace(/px$/, '');
  413.       }
  414.       return value;
  415.     };
  416.  
  417.     var addPixelSuffix = function (value) {
  418.       if (value.length > 0 && /^[0-9]+$/.test(value)) {
  419.         value += 'px';
  420.       }
  421.       return value;
  422.     };
  423.  
  424.     var mergeMargins = function (css) {
  425.       if (css.margin) {
  426.  
  427.         var splitMargin = css.margin.split(" ");
  428.  
  429.         switch (splitMargin.length) {
  430.           case 1: //margin: toprightbottomleft;
  431.             css['margin-top'] = css['margin-top'] || splitMargin[0];
  432.             css['margin-right'] = css['margin-right'] || splitMargin[0];
  433.             css['margin-bottom'] = css['margin-bottom'] || splitMargin[0];
  434.             css['margin-left'] = css['margin-left'] || splitMargin[0];
  435.             break;
  436.           case 2: //margin: topbottom rightleft;
  437.             css['margin-top'] = css['margin-top'] || splitMargin[0];
  438.             css['margin-right'] = css['margin-right'] || splitMargin[1];
  439.             css['margin-bottom'] = css['margin-bottom'] || splitMargin[0];
  440.             css['margin-left'] = css['margin-left'] || splitMargin[1];
  441.             break;
  442.           case 3: //margin: top rightleft bottom;
  443.             css['margin-top'] = css['margin-top'] || splitMargin[0];
  444.             css['margin-right'] = css['margin-right'] || splitMargin[1];
  445.             css['margin-bottom'] = css['margin-bottom'] || splitMargin[2];
  446.             css['margin-left'] = css['margin-left'] || splitMargin[1];
  447.             break;
  448.           case 4: //margin: top right bottom left;
  449.             css['margin-top'] = css['margin-top'] || splitMargin[0];
  450.             css['margin-right'] = css['margin-right'] || splitMargin[1];
  451.             css['margin-bottom'] = css['margin-bottom'] || splitMargin[2];
  452.             css['margin-left'] = css['margin-left'] || splitMargin[3];
  453.         }
  454.         delete css.margin;
  455.       }
  456.       return css;
  457.     };
  458.  
  459.     return {
  460.       getImageSize: getImageSize,
  461.       buildListItems: buildListItems,
  462.       removePixelSuffix: removePixelSuffix,
  463.       addPixelSuffix: addPixelSuffix,
  464.       mergeMargins: mergeMargins
  465.     };
  466.   }
  467. );
  468.  
  469. /**
  470.  * Dialog.js
  471.  *
  472.  * Released under LGPL License.
  473.  * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
  474.  *
  475.  * License: http://www.tinymce.com/license
  476.  * Contributing: http://www.tinymce.com/contributing
  477.  */
  478.  
  479. /**
  480.  * @class tinymce.image.ui.Dialog
  481.  * @private
  482.  */
  483. define(
  484.   'tinymce.plugins.image.ui.Dialog',
  485.   [
  486.     'global!document',
  487.     'global!Math',
  488.     'global!RegExp',
  489.     'tinymce.core.Env',
  490.     'tinymce.core.ui.Factory',
  491.     'tinymce.core.util.JSON',
  492.     'tinymce.core.util.Tools',
  493.     'tinymce.core.util.XHR',
  494.     'tinymce.plugins.image.core.Uploader',
  495.     'tinymce.plugins.image.core.Utils'
  496.   ],
  497.   function (document, Math, RegExp, Env, Factory, JSON, Tools, XHR, Uploader, Utils) {
  498.  
  499.     return function (editor) {
  500.       function createImageList(callback) {
  501.         var imageList = editor.settings.image_list;
  502.  
  503.         if (typeof imageList == "string") {
  504.           XHR.send({
  505.             url: imageList,
  506.             success: function (text) {
  507.               callback(JSON.parse(text));
  508.             }
  509.           });
  510.         } else if (typeof imageList == "function") {
  511.           imageList(callback);
  512.         } else {
  513.           callback(imageList);
  514.         }
  515.       }
  516.  
  517.       function showDialog(imageList) {
  518.         var win, data = {}, imgElm, figureElm, dom = editor.dom, settings = editor.settings;
  519.         var width, height, imageListCtrl, classListCtrl, imageDimensions = settings.image_dimensions !== false;
  520.  
  521.  
  522.         function onFileInput() {
  523.           var Throbber = Factory.get('Throbber');
  524.           var throbber = new Throbber(win.getEl());
  525.           var file = this.value();
  526.  
  527.           var uploader = new Uploader({
  528.             url: settings.images_upload_url,
  529.             basePath: settings.images_upload_base_path,
  530.             credentials: settings.images_upload_credentials,
  531.             handler: settings.images_upload_handler
  532.           });
  533.  
  534.           // we do not need to add this to editors blobCache, so we fake bare minimum
  535.           var blobInfo = editor.editorUpload.blobCache.create({
  536.             blob: file,
  537.             name: file.name ? file.name.replace(/\.[^\.]+$/, '') : null, // strip extension
  538.             base64: 'data:image/fake;base64,=' // without this create() will throw exception
  539.           });
  540.  
  541.           var finalize = function () {
  542.             throbber.hide();
  543.             URL.revokeObjectURL(blobInfo.blobUri()); // in theory we could fake blobUri too, but until it's legitimate, we have too revoke it manually
  544.           };
  545.  
  546.           throbber.show();
  547.  
  548.           return uploader.upload(blobInfo).then(function (url) {
  549.             var src = win.find('#src');
  550.             src.value(url);
  551.             win.find('tabpanel')[0].activateTab(0); // switch to General tab
  552.             src.fire('change'); // this will invoke onSrcChange (and any other handlers, if any).
  553.             finalize();
  554.             return url;
  555.           }, function (err) {
  556.             editor.windowManager.alert(err);
  557.             finalize();
  558.           });
  559.         }
  560.  
  561.         function isTextBlock(node) {
  562.           return editor.schema.getTextBlockElements()[node.nodeName];
  563.         }
  564.  
  565.         function recalcSize() {
  566.           var widthCtrl, heightCtrl, newWidth, newHeight;
  567.  
  568.           widthCtrl = win.find('#width')[0];
  569.           heightCtrl = win.find('#height')[0];
  570.  
  571.           if (!widthCtrl || !heightCtrl) {
  572.             return;
  573.           }
  574.  
  575.           newWidth = widthCtrl.value();
  576.           newHeight = heightCtrl.value();
  577.  
  578.           if (win.find('#constrain')[0].checked() && width && height && newWidth && newHeight) {
  579.             if (width != newWidth) {
  580.               newHeight = Math.round((newWidth / width) * newHeight);
  581.  
  582.               if (!isNaN(newHeight)) {
  583.                 heightCtrl.value(newHeight);
  584.               }
  585.             } else {
  586.               newWidth = Math.round((newHeight / height) * newWidth);
  587.  
  588.               if (!isNaN(newWidth)) {
  589.                 widthCtrl.value(newWidth);
  590.               }
  591.             }
  592.           }
  593.  
  594.           width = newWidth;
  595.           height = newHeight;
  596.         }
  597.  
  598.         function updateStyle() {
  599.           if (!editor.settings.image_advtab) {
  600.             return;
  601.           }
  602.  
  603.           var data = win.toJSON(),
  604.             css = dom.parseStyle(data.style);
  605.  
  606.           css = Utils.mergeMargins(css);
  607.  
  608.           if (data.vspace) {
  609.             css['margin-top'] = css['margin-bottom'] = Utils.addPixelSuffix(data.vspace);
  610.           }
  611.           if (data.hspace) {
  612.             css['margin-left'] = css['margin-right'] = Utils.addPixelSuffix(data.hspace);
  613.           }
  614.           if (data.border) {
  615.             css['border-width'] = Utils.addPixelSuffix(data.border);
  616.           }
  617.  
  618.           win.find('#style').value(dom.serializeStyle(dom.parseStyle(dom.serializeStyle(css))));
  619.         }
  620.  
  621.         function updateVSpaceHSpaceBorder() {
  622.           if (!editor.settings.image_advtab) {
  623.             return;
  624.           }
  625.  
  626.           var data = win.toJSON(),
  627.             css = dom.parseStyle(data.style);
  628.  
  629.           win.find('#vspace').value("");
  630.           win.find('#hspace').value("");
  631.  
  632.           css = Utils.mergeMargins(css);
  633.  
  634.           //Move opposite equal margins to vspace/hspace field
  635.           if ((css['margin-top'] && css['margin-bottom']) || (css['margin-right'] && css['margin-left'])) {
  636.             if (css['margin-top'] === css['margin-bottom']) {
  637.               win.find('#vspace').value(Utils.removePixelSuffix(css['margin-top']));
  638.             } else {
  639.               win.find('#vspace').value('');
  640.             }
  641.             if (css['margin-right'] === css['margin-left']) {
  642.               win.find('#hspace').value(Utils.removePixelSuffix(css['margin-right']));
  643.             } else {
  644.               win.find('#hspace').value('');
  645.             }
  646.           }
  647.  
  648.           //Move border-width
  649.           if (css['border-width']) {
  650.             win.find('#border').value(Utils.removePixelSuffix(css['border-width']));
  651.           }
  652.  
  653.           win.find('#style').value(dom.serializeStyle(dom.parseStyle(dom.serializeStyle(css))));
  654.         }
  655.  
  656.         function waitLoad(imgElm) {
  657.           function selectImage() {
  658.             imgElm.onload = imgElm.onerror = null;
  659.  
  660.             if (editor.selection) {
  661.               editor.selection.select(imgElm);
  662.               editor.nodeChanged();
  663.             }
  664.           }
  665.  
  666.           imgElm.onload = function () {
  667.             if (!data.width && !data.height && imageDimensions) {
  668.               dom.setAttribs(imgElm, {
  669.                 width: imgElm.clientWidth,
  670.                 height: imgElm.clientHeight
  671.               });
  672.             }
  673.  
  674.             selectImage();
  675.           };
  676.  
  677.           imgElm.onerror = selectImage;
  678.         }
  679.  
  680.         function onSubmitForm() {
  681.           var figureElm, oldImg;
  682.  
  683.           updateStyle();
  684.           recalcSize();
  685.  
  686.           data = Tools.extend(data, win.toJSON());
  687.  
  688.           if (!data.alt) {
  689.             data.alt = '';
  690.           }
  691.  
  692.           if (!data.title) {
  693.             data.title = '';
  694.           }
  695.  
  696.           if (data.width === '') {
  697.             data.width = null;
  698.           }
  699.  
  700.           if (data.height === '') {
  701.             data.height = null;
  702.           }
  703.  
  704.           if (!data.style) {
  705.             data.style = null;
  706.           }
  707.  
  708.           // Setup new data excluding style properties
  709.           /*eslint dot-notation: 0*/
  710.           data = {
  711.             src: data.src,
  712.             alt: data.alt,
  713.             title: data.title,
  714.             width: data.width,
  715.             height: data.height,
  716.             style: data.style,
  717.             caption: data.caption,
  718.             "class": data["class"]
  719.           };
  720.  
  721.           editor.undoManager.transact(function () {
  722.             if (!data.src) {
  723.               if (imgElm) {
  724.                 var elm = dom.is(imgElm.parentNode, 'figure.image') ? imgElm.parentNode : imgElm;
  725.                 dom.remove(elm);
  726.                 editor.focus();
  727.                 editor.nodeChanged();
  728.  
  729.                 if (dom.isEmpty(editor.getBody())) {
  730.                   editor.setContent('');
  731.                   editor.selection.setCursorLocation();
  732.                 }
  733.               }
  734.  
  735.               return;
  736.             }
  737.  
  738.             if (data.title === "") {
  739.               data.title = null;
  740.             }
  741.  
  742.             if (!imgElm) {
  743.               data.id = '__mcenew';
  744.               editor.focus();
  745.               editor.selection.setContent(dom.createHTML('img', data));
  746.               imgElm = dom.get('__mcenew');
  747.               dom.setAttrib(imgElm, 'id', null);
  748.             } else {
  749.               dom.setAttribs(imgElm, data);
  750.             }
  751.  
  752.             editor.editorUpload.uploadImagesAuto();
  753.  
  754.             if (data.caption === false) {
  755.               if (dom.is(imgElm.parentNode, 'figure.image')) {
  756.                 figureElm = imgElm.parentNode;
  757.                 dom.setAttrib(imgElm, 'contenteditable', null);
  758.                 dom.insertAfter(imgElm, figureElm);
  759.                 dom.remove(figureElm);
  760.                 editor.selection.select(imgElm);
  761.                 editor.nodeChanged();
  762.               }
  763.             }
  764.  
  765.             if (data.caption === true) {
  766.               if (!dom.is(imgElm.parentNode, 'figure.image')) {
  767.                 oldImg = imgElm;
  768.                 imgElm = imgElm.cloneNode(true);
  769.                 imgElm.contentEditable = true;
  770.                 figureElm = dom.create('figure', { 'class': 'image' });
  771.                 figureElm.appendChild(imgElm);
  772.                 figureElm.appendChild(dom.create('figcaption', { contentEditable: true }, 'Caption'));
  773.                 figureElm.contentEditable = false;
  774.  
  775.                 var textBlock = dom.getParent(oldImg, isTextBlock);
  776.                 if (textBlock) {
  777.                   dom.split(textBlock, oldImg, figureElm);
  778.                 } else {
  779.                   dom.replace(figureElm, oldImg);
  780.                 }
  781.  
  782.                 editor.selection.select(figureElm);
  783.               }
  784.  
  785.               return;
  786.             }
  787.  
  788.             waitLoad(imgElm);
  789.           });
  790.         }
  791.  
  792.         function onSrcChange(e) {
  793.           var srcURL, prependURL, absoluteURLPattern, meta = e.meta || {};
  794.  
  795.           if (imageListCtrl) {
  796.             imageListCtrl.value(editor.convertURL(this.value(), 'src'));
  797.           }
  798.  
  799.           Tools.each(meta, function (value, key) {
  800.             win.find('#' + key).value(value);
  801.           });
  802.  
  803.           if (!meta.width && !meta.height) {
  804.             srcURL = editor.convertURL(this.value(), 'src');
  805.  
  806.             // Pattern test the src url and make sure we haven't already prepended the url
  807.             prependURL = editor.settings.image_prepend_url;
  808.             absoluteURLPattern = new RegExp('^(?:[a-z]+:)?//', 'i');
  809.             if (prependURL && !absoluteURLPattern.test(srcURL) && srcURL.substring(0, prependURL.length) !== prependURL) {
  810.               srcURL = prependURL + srcURL;
  811.             }
  812.  
  813.             this.value(srcURL);
  814.  
  815.             Utils.getImageSize(editor.documentBaseURI.toAbsolute(this.value()), function (data) {
  816.               if (data.width && data.height && imageDimensions) {
  817.                 width = data.width;
  818.                 height = data.height;
  819.  
  820.                 win.find('#width').value(width);
  821.                 win.find('#height').value(height);
  822.               }
  823.             });
  824.           }
  825.         }
  826.  
  827.         function onBeforeCall(e) {
  828.           e.meta = win.toJSON();
  829.         }
  830.  
  831.         imgElm = editor.selection.getNode();
  832.         figureElm = dom.getParent(imgElm, 'figure.image');
  833.         if (figureElm) {
  834.           imgElm = dom.select('img', figureElm)[0];
  835.         }
  836.  
  837.         if (imgElm &&
  838.           (imgElm.nodeName != 'IMG' ||
  839.             imgElm.getAttribute('data-mce-object') ||
  840.             imgElm.getAttribute('data-mce-placeholder'))) {
  841.           imgElm = null;
  842.         }
  843.  
  844.         if (imgElm) {
  845.           width = dom.getAttrib(imgElm, 'width');
  846.           height = dom.getAttrib(imgElm, 'height');
  847.  
  848.           data = {
  849.             src: dom.getAttrib(imgElm, 'src'),
  850.             alt: dom.getAttrib(imgElm, 'alt'),
  851.             title: dom.getAttrib(imgElm, 'title'),
  852.             "class": dom.getAttrib(imgElm, 'class'),
  853.             width: width,
  854.             height: height,
  855.             caption: !!figureElm
  856.           };
  857.         }
  858.  
  859.         if (imageList) {
  860.           imageListCtrl = {
  861.             type: 'listbox',
  862.             label: 'Image list',
  863.             values: Utils.buildListItems(
  864.               imageList,
  865.               function (item) {
  866.                 item.value = editor.convertURL(item.value || item.url, 'src');
  867.               },
  868.               [{ text: 'None', value: '' }]
  869.             ),
  870.             value: data.src && editor.convertURL(data.src, 'src'),
  871.             onselect: function (e) {
  872.               var altCtrl = win.find('#alt');
  873.  
  874.               if (!altCtrl.value() || (e.lastControl && altCtrl.value() == e.lastControl.text())) {
  875.                 altCtrl.value(e.control.text());
  876.               }
  877.  
  878.               win.find('#src').value(e.control.value()).fire('change');
  879.             },
  880.             onPostRender: function () {
  881.               /*eslint consistent-this: 0*/
  882.               imageListCtrl = this;
  883.             }
  884.           };
  885.         }
  886.  
  887.         if (editor.settings.image_class_list) {
  888.           classListCtrl = {
  889.             name: 'class',
  890.             type: 'listbox',
  891.             label: 'Class',
  892.             values: Utils.buildListItems(
  893.               editor.settings.image_class_list,
  894.               function (item) {
  895.                 if (item.value) {
  896.                   item.textStyle = function () {
  897.                     return editor.formatter.getCssText({ inline: 'img', classes: [item.value] });
  898.                   };
  899.                 }
  900.               }
  901.             )
  902.           };
  903.         }
  904.  
  905.         // General settings shared between simple and advanced dialogs
  906.         var generalFormItems = [
  907.           {
  908.             name: 'src',
  909.             type: 'filepicker',
  910.             filetype: 'image',
  911.             label: 'Source',
  912.             autofocus: true,
  913.             onchange: onSrcChange,
  914.             onbeforecall: onBeforeCall
  915.           },
  916.           imageListCtrl
  917.         ];
  918.  
  919.         if (editor.settings.image_description !== false) {
  920.           generalFormItems.push({ name: 'alt', type: 'textbox', label: 'Image description' });
  921.         }
  922.  
  923.         if (editor.settings.image_title) {
  924.           generalFormItems.push({ name: 'title', type: 'textbox', label: 'Image Title' });
  925.         }
  926.  
  927.         if (imageDimensions) {
  928.           generalFormItems.push({
  929.             type: 'container',
  930.             label: 'Dimensions',
  931.             layout: 'flex',
  932.             direction: 'row',
  933.             align: 'center',
  934.             spacing: 5,
  935.             items: [
  936.               { name: 'width', type: 'textbox', maxLength: 5, size: 3, onchange: recalcSize, ariaLabel: 'Width' },
  937.               { type: 'label', text: 'x' },
  938.               { name: 'height', type: 'textbox', maxLength: 5, size: 3, onchange: recalcSize, ariaLabel: 'Height' },
  939.               { name: 'constrain', type: 'checkbox', checked: true, text: 'Constrain proportions' }
  940.             ]
  941.           });
  942.         }
  943.  
  944.         generalFormItems.push(classListCtrl);
  945.  
  946.         if (editor.settings.image_caption && Env.ceFalse) {
  947.           generalFormItems.push({ name: 'caption', type: 'checkbox', label: 'Caption' });
  948.         }
  949.  
  950.         if (editor.settings.image_advtab || editor.settings.images_upload_url) {
  951.           var body = [
  952.             {
  953.               title: 'General',
  954.               type: 'form',
  955.               items: generalFormItems
  956.             }
  957.           ];
  958.  
  959.           if (editor.settings.image_advtab) {
  960.             // Parse styles from img
  961.             if (imgElm) {
  962.               if (imgElm.style.marginLeft && imgElm.style.marginRight && imgElm.style.marginLeft === imgElm.style.marginRight) {
  963.                 data.hspace = Utils.removePixelSuffix(imgElm.style.marginLeft);
  964.               }
  965.               if (imgElm.style.marginTop && imgElm.style.marginBottom && imgElm.style.marginTop === imgElm.style.marginBottom) {
  966.                 data.vspace = Utils.removePixelSuffix(imgElm.style.marginTop);
  967.               }
  968.               if (imgElm.style.borderWidth) {
  969.                 data.border = Utils.removePixelSuffix(imgElm.style.borderWidth);
  970.               }
  971.  
  972.               data.style = editor.dom.serializeStyle(editor.dom.parseStyle(editor.dom.getAttrib(imgElm, 'style')));
  973.             }
  974.  
  975.             body.push({
  976.               title: 'Advanced',
  977.               type: 'form',
  978.               pack: 'start',
  979.               items: [
  980.                 {
  981.                   label: 'Style',
  982.                   name: 'style',
  983.                   type: 'textbox',
  984.                   onchange: updateVSpaceHSpaceBorder
  985.                 },
  986.                 {
  987.                   type: 'form',
  988.                   layout: 'grid',
  989.                   packV: 'start',
  990.                   columns: 2,
  991.                   padding: 0,
  992.                   alignH: ['left', 'right'],
  993.                   defaults: {
  994.                     type: 'textbox',
  995.                     maxWidth: 50,
  996.                     onchange: updateStyle
  997.                   },
  998.                   items: [
  999.                     { label: 'Vertical space', name: 'vspace' },
  1000.                     { label: 'Horizontal space', name: 'hspace' },
  1001.                     { label: 'Border', name: 'border' }
  1002.                   ]
  1003.                 }
  1004.               ]
  1005.             });
  1006.           }
  1007.  
  1008.           if (editor.settings.images_upload_url) {
  1009.             var acceptExts = '.jpg,.jpeg,.png,.gif';
  1010.  
  1011.             var uploadTab = {
  1012.               title: 'Upload',
  1013.               type: 'form',
  1014.               layout: 'flex',
  1015.               direction: 'column',
  1016.               align: 'stretch',
  1017.               padding: '20 20 20 20',
  1018.               items: [
  1019.                 {
  1020.                   type: 'container',
  1021.                   layout: 'flex',
  1022.                   direction: 'column',
  1023.                   align: 'center',
  1024.                   spacing: 10,
  1025.                   items: [
  1026.                     {
  1027.                       text: "Browse for an image",
  1028.                       type: 'browsebutton',
  1029.                       accept: acceptExts,
  1030.                       onchange: onFileInput
  1031.                     },
  1032.                     {
  1033.                       text: 'OR',
  1034.                       type: 'label'
  1035.                     }
  1036.                   ]
  1037.                 },
  1038.                 {
  1039.                   text: "Drop an image here",
  1040.                   type: 'dropzone',
  1041.                   accept: acceptExts,
  1042.                   height: 100,
  1043.                   onchange: onFileInput
  1044.                 }
  1045.               ]
  1046.             };
  1047.  
  1048.             body.push(uploadTab);
  1049.           }
  1050.  
  1051.           // Advanced dialog shows general+advanced tabs
  1052.           win = editor.windowManager.open({
  1053.             title: 'Insert/edit image',
  1054.             data: data,
  1055.             bodyType: 'tabpanel',
  1056.             body: body,
  1057.             onSubmit: onSubmitForm
  1058.           });
  1059.         } else {
  1060.           // Simple default dialog
  1061.           win = editor.windowManager.open({
  1062.             title: 'Insert/edit image',
  1063.             data: data,
  1064.             body: generalFormItems,
  1065.             onSubmit: onSubmitForm
  1066.           });
  1067.         }
  1068.       }
  1069.  
  1070.       function open() {
  1071.         createImageList(showDialog);
  1072.       }
  1073.  
  1074.       return {
  1075.         open: open
  1076.       };
  1077.     };
  1078.   }
  1079. );
  1080.  
  1081. /**
  1082.  * Plugin.js
  1083.  *
  1084.  * Released under LGPL License.
  1085.  * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
  1086.  *
  1087.  * License: http://www.tinymce.com/license
  1088.  * Contributing: http://www.tinymce.com/contributing
  1089.  */
  1090.  
  1091. /**
  1092.  * This class contains all core logic for the image plugin.
  1093.  *
  1094.  * @class tinymce.image.Plugin
  1095.  * @private
  1096.  */
  1097. define(
  1098.   'tinymce.plugins.image.Plugin',
  1099.   [
  1100.     'tinymce.core.PluginManager',
  1101.     'tinymce.core.util.Tools',
  1102.     'tinymce.plugins.image.ui.Dialog'
  1103.   ],
  1104.   function (PluginManager, Tools, Dialog) {
  1105.     PluginManager.add('image', function (editor) {
  1106.  
  1107.       editor.on('preInit', function () {
  1108.         function hasImageClass(node) {
  1109.           var className = node.attr('class');
  1110.           return className && /\bimage\b/.test(className);
  1111.         }
  1112.  
  1113.         function toggleContentEditableState(state) {
  1114.           return function (nodes) {
  1115.             var i = nodes.length, node;
  1116.  
  1117.             function toggleContentEditable(node) {
  1118.               node.attr('contenteditable', state ? 'true' : null);
  1119.             }
  1120.  
  1121.             while (i--) {
  1122.               node = nodes[i];
  1123.  
  1124.               if (hasImageClass(node)) {
  1125.                 node.attr('contenteditable', state ? 'false' : null);
  1126.                 Tools.each(node.getAll('figcaption'), toggleContentEditable);
  1127.                 Tools.each(node.getAll('img'), toggleContentEditable);
  1128.               }
  1129.             }
  1130.           };
  1131.         }
  1132.  
  1133.         editor.parser.addNodeFilter('figure', toggleContentEditableState(true));
  1134.         editor.serializer.addNodeFilter('figure', toggleContentEditableState(false));
  1135.       });
  1136.  
  1137.       editor.addButton('image', {
  1138.         icon: 'image',
  1139.         tooltip: 'Insert/edit image',
  1140.         onclick: Dialog(editor).open,
  1141.         stateSelector: 'img:not([data-mce-object],[data-mce-placeholder]),figure.image'
  1142.       });
  1143.  
  1144.       editor.addMenuItem('image', {
  1145.         icon: 'image',
  1146.         text: 'Image',
  1147.         onclick: Dialog(editor).open,
  1148.         context: 'insert',
  1149.         prependToContext: true
  1150.       });
  1151.  
  1152.       editor.addCommand('mceImage', Dialog(editor).open);
  1153.     });
  1154.  
  1155.     return function () { };
  1156.   }
  1157. );
  1158. dem('tinymce.plugins.image.Plugin')();
  1159. })();
  1160.