plugin.js 53 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710
  1. /**
  2. * Copyright (c) Tiny Technologies, Inc. All rights reserved.
  3. * Licensed under the LGPL or a commercial license.
  4. * For LGPL see License.txt in the project root for license information.
  5. * For commercial licenses see https://www.tiny.cloud/
  6. *
  7. * Version: 5.1.0 (2019-10-17)
  8. */
  9. (function (domGlobals) {
  10. 'use strict';
  11. var Cell = function (initial) {
  12. var value = initial;
  13. var get = function () {
  14. return value;
  15. };
  16. var set = function (v) {
  17. value = v;
  18. };
  19. var clone = function () {
  20. return Cell(get());
  21. };
  22. return {
  23. get: get,
  24. set: set,
  25. clone: clone
  26. };
  27. };
  28. var global = tinymce.util.Tools.resolve('tinymce.PluginManager');
  29. var global$1 = tinymce.util.Tools.resolve('tinymce.util.Tools');
  30. var noop = function () {
  31. };
  32. var constant = function (value) {
  33. return function () {
  34. return value;
  35. };
  36. };
  37. var never = constant(false);
  38. var always = constant(true);
  39. var none = function () {
  40. return NONE;
  41. };
  42. var NONE = function () {
  43. var eq = function (o) {
  44. return o.isNone();
  45. };
  46. var call = function (thunk) {
  47. return thunk();
  48. };
  49. var id = function (n) {
  50. return n;
  51. };
  52. var me = {
  53. fold: function (n, s) {
  54. return n();
  55. },
  56. is: never,
  57. isSome: never,
  58. isNone: always,
  59. getOr: id,
  60. getOrThunk: call,
  61. getOrDie: function (msg) {
  62. throw new Error(msg || 'error: getOrDie called on none.');
  63. },
  64. getOrNull: constant(null),
  65. getOrUndefined: constant(undefined),
  66. or: id,
  67. orThunk: call,
  68. map: none,
  69. each: noop,
  70. bind: none,
  71. exists: never,
  72. forall: always,
  73. filter: none,
  74. equals: eq,
  75. equals_: eq,
  76. toArray: function () {
  77. return [];
  78. },
  79. toString: constant('none()')
  80. };
  81. if (Object.freeze) {
  82. Object.freeze(me);
  83. }
  84. return me;
  85. }();
  86. var some = function (a) {
  87. var constant_a = constant(a);
  88. var self = function () {
  89. return me;
  90. };
  91. var bind = function (f) {
  92. return f(a);
  93. };
  94. var me = {
  95. fold: function (n, s) {
  96. return s(a);
  97. },
  98. is: function (v) {
  99. return a === v;
  100. },
  101. isSome: always,
  102. isNone: never,
  103. getOr: constant_a,
  104. getOrThunk: constant_a,
  105. getOrDie: constant_a,
  106. getOrNull: constant_a,
  107. getOrUndefined: constant_a,
  108. or: self,
  109. orThunk: self,
  110. map: function (f) {
  111. return some(f(a));
  112. },
  113. each: function (f) {
  114. f(a);
  115. },
  116. bind: bind,
  117. exists: bind,
  118. forall: bind,
  119. filter: function (f) {
  120. return f(a) ? me : NONE;
  121. },
  122. toArray: function () {
  123. return [a];
  124. },
  125. toString: function () {
  126. return 'some(' + a + ')';
  127. },
  128. equals: function (o) {
  129. return o.is(a);
  130. },
  131. equals_: function (o, elementEq) {
  132. return o.fold(never, function (b) {
  133. return elementEq(a, b);
  134. });
  135. }
  136. };
  137. return me;
  138. };
  139. var from = function (value) {
  140. return value === null || value === undefined ? NONE : some(value);
  141. };
  142. var Option = {
  143. some: some,
  144. none: none,
  145. from: from
  146. };
  147. function create(width, height) {
  148. return resize(domGlobals.document.createElement('canvas'), width, height);
  149. }
  150. function clone(canvas) {
  151. var tCanvas = create(canvas.width, canvas.height);
  152. var ctx = get2dContext(tCanvas);
  153. ctx.drawImage(canvas, 0, 0);
  154. return tCanvas;
  155. }
  156. function get2dContext(canvas) {
  157. return canvas.getContext('2d');
  158. }
  159. function resize(canvas, width, height) {
  160. canvas.width = width;
  161. canvas.height = height;
  162. return canvas;
  163. }
  164. function getWidth(image) {
  165. return image.naturalWidth || image.width;
  166. }
  167. function getHeight(image) {
  168. return image.naturalHeight || image.height;
  169. }
  170. var promise = function () {
  171. var Promise = function (fn) {
  172. if (typeof this !== 'object') {
  173. throw new TypeError('Promises must be constructed via new');
  174. }
  175. if (typeof fn !== 'function') {
  176. throw new TypeError('not a function');
  177. }
  178. this._state = null;
  179. this._value = null;
  180. this._deferreds = [];
  181. doResolve(fn, bind(resolve, this), bind(reject, this));
  182. };
  183. var asap = Promise.immediateFn || typeof window.setImmediate === 'function' && window.setImmediate || function (fn) {
  184. domGlobals.setTimeout(fn, 1);
  185. };
  186. function bind(fn, thisArg) {
  187. return function () {
  188. return fn.apply(thisArg, arguments);
  189. };
  190. }
  191. var isArray = Array.isArray || function (value) {
  192. return Object.prototype.toString.call(value) === '[object Array]';
  193. };
  194. function handle(deferred) {
  195. var me = this;
  196. if (this._state === null) {
  197. this._deferreds.push(deferred);
  198. return;
  199. }
  200. asap(function () {
  201. var cb = me._state ? deferred.onFulfilled : deferred.onRejected;
  202. if (cb === null) {
  203. (me._state ? deferred.resolve : deferred.reject)(me._value);
  204. return;
  205. }
  206. var ret;
  207. try {
  208. ret = cb(me._value);
  209. } catch (e) {
  210. deferred.reject(e);
  211. return;
  212. }
  213. deferred.resolve(ret);
  214. });
  215. }
  216. function resolve(newValue) {
  217. try {
  218. if (newValue === this) {
  219. throw new TypeError('A promise cannot be resolved with itself.');
  220. }
  221. if (newValue && (typeof newValue === 'object' || typeof newValue === 'function')) {
  222. var then = newValue.then;
  223. if (typeof then === 'function') {
  224. doResolve(bind(then, newValue), bind(resolve, this), bind(reject, this));
  225. return;
  226. }
  227. }
  228. this._state = true;
  229. this._value = newValue;
  230. finale.call(this);
  231. } catch (e) {
  232. reject.call(this, e);
  233. }
  234. }
  235. function reject(newValue) {
  236. this._state = false;
  237. this._value = newValue;
  238. finale.call(this);
  239. }
  240. function finale() {
  241. for (var _i = 0, _a = this._deferreds; _i < _a.length; _i++) {
  242. var deferred = _a[_i];
  243. handle.call(this, deferred);
  244. }
  245. this._deferreds = [];
  246. }
  247. function Handler(onFulfilled, onRejected, resolve, reject) {
  248. this.onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : null;
  249. this.onRejected = typeof onRejected === 'function' ? onRejected : null;
  250. this.resolve = resolve;
  251. this.reject = reject;
  252. }
  253. function doResolve(fn, onFulfilled, onRejected) {
  254. var done = false;
  255. try {
  256. fn(function (value) {
  257. if (done) {
  258. return;
  259. }
  260. done = true;
  261. onFulfilled(value);
  262. }, function (reason) {
  263. if (done) {
  264. return;
  265. }
  266. done = true;
  267. onRejected(reason);
  268. });
  269. } catch (ex) {
  270. if (done) {
  271. return;
  272. }
  273. done = true;
  274. onRejected(ex);
  275. }
  276. }
  277. Promise.prototype.catch = function (onRejected) {
  278. return this.then(null, onRejected);
  279. };
  280. Promise.prototype.then = function (onFulfilled, onRejected) {
  281. var me = this;
  282. return new Promise(function (resolve, reject) {
  283. handle.call(me, new Handler(onFulfilled, onRejected, resolve, reject));
  284. });
  285. };
  286. Promise.all = function () {
  287. var values = [];
  288. for (var _i = 0; _i < arguments.length; _i++) {
  289. values[_i] = arguments[_i];
  290. }
  291. var args = Array.prototype.slice.call(values.length === 1 && isArray(values[0]) ? values[0] : values);
  292. return new Promise(function (resolve, reject) {
  293. if (args.length === 0) {
  294. return resolve([]);
  295. }
  296. var remaining = args.length;
  297. function res(i, val) {
  298. try {
  299. if (val && (typeof val === 'object' || typeof val === 'function')) {
  300. var then = val.then;
  301. if (typeof then === 'function') {
  302. then.call(val, function (val) {
  303. res(i, val);
  304. }, reject);
  305. return;
  306. }
  307. }
  308. args[i] = val;
  309. if (--remaining === 0) {
  310. resolve(args);
  311. }
  312. } catch (ex) {
  313. reject(ex);
  314. }
  315. }
  316. for (var i = 0; i < args.length; i++) {
  317. res(i, args[i]);
  318. }
  319. });
  320. };
  321. Promise.resolve = function (value) {
  322. if (value && typeof value === 'object' && value.constructor === Promise) {
  323. return value;
  324. }
  325. return new Promise(function (resolve) {
  326. resolve(value);
  327. });
  328. };
  329. Promise.reject = function (reason) {
  330. return new Promise(function (resolve, reject) {
  331. reject(reason);
  332. });
  333. };
  334. Promise.race = function (values) {
  335. return new Promise(function (resolve, reject) {
  336. for (var _i = 0, values_1 = values; _i < values_1.length; _i++) {
  337. var value = values_1[_i];
  338. value.then(resolve, reject);
  339. }
  340. });
  341. };
  342. return Promise;
  343. };
  344. var Promise = window.Promise ? window.Promise : promise();
  345. function imageToBlob(image) {
  346. var src = image.src;
  347. if (src.indexOf('data:') === 0) {
  348. return dataUriToBlob(src);
  349. }
  350. return anyUriToBlob(src);
  351. }
  352. function blobToImage(blob) {
  353. return new Promise(function (resolve, reject) {
  354. var blobUrl = domGlobals.URL.createObjectURL(blob);
  355. var image = new domGlobals.Image();
  356. var removeListeners = function () {
  357. image.removeEventListener('load', loaded);
  358. image.removeEventListener('error', error);
  359. };
  360. function loaded() {
  361. removeListeners();
  362. resolve(image);
  363. }
  364. function error() {
  365. removeListeners();
  366. reject('Unable to load data of type ' + blob.type + ': ' + blobUrl);
  367. }
  368. image.addEventListener('load', loaded);
  369. image.addEventListener('error', error);
  370. image.src = blobUrl;
  371. if (image.complete) {
  372. loaded();
  373. }
  374. });
  375. }
  376. function anyUriToBlob(url) {
  377. return new Promise(function (resolve, reject) {
  378. var xhr = new domGlobals.XMLHttpRequest();
  379. xhr.open('GET', url, true);
  380. xhr.responseType = 'blob';
  381. xhr.onload = function () {
  382. if (this.status === 200) {
  383. resolve(this.response);
  384. }
  385. };
  386. xhr.onerror = function () {
  387. var _this = this;
  388. var corsError = function () {
  389. var obj = new Error('No access to download image');
  390. obj.code = 18;
  391. obj.name = 'SecurityError';
  392. return obj;
  393. };
  394. var genericError = function () {
  395. return new Error('Error ' + _this.status + ' downloading image');
  396. };
  397. reject(this.status === 0 ? corsError() : genericError());
  398. };
  399. xhr.send();
  400. });
  401. }
  402. function dataUriToBlobSync(uri) {
  403. var data = uri.split(',');
  404. var matches = /data:([^;]+)/.exec(data[0]);
  405. if (!matches) {
  406. return Option.none();
  407. }
  408. var mimetype = matches[1];
  409. var base64 = data[1];
  410. var sliceSize = 1024;
  411. var byteCharacters = domGlobals.atob(base64);
  412. var bytesLength = byteCharacters.length;
  413. var slicesCount = Math.ceil(bytesLength / sliceSize);
  414. var byteArrays = new Array(slicesCount);
  415. for (var sliceIndex = 0; sliceIndex < slicesCount; ++sliceIndex) {
  416. var begin = sliceIndex * sliceSize;
  417. var end = Math.min(begin + sliceSize, bytesLength);
  418. var bytes = new Array(end - begin);
  419. for (var offset = begin, i = 0; offset < end; ++i, ++offset) {
  420. bytes[i] = byteCharacters[offset].charCodeAt(0);
  421. }
  422. byteArrays[sliceIndex] = new Uint8Array(bytes);
  423. }
  424. return Option.some(new domGlobals.Blob(byteArrays, { type: mimetype }));
  425. }
  426. function dataUriToBlob(uri) {
  427. return new Promise(function (resolve, reject) {
  428. dataUriToBlobSync(uri).fold(function () {
  429. reject('uri is not base64: ' + uri);
  430. }, resolve);
  431. });
  432. }
  433. function canvasToBlob(canvas, type, quality) {
  434. type = type || 'image/png';
  435. if (domGlobals.HTMLCanvasElement.prototype.toBlob) {
  436. return new Promise(function (resolve, reject) {
  437. canvas.toBlob(function (blob) {
  438. if (blob) {
  439. resolve(blob);
  440. } else {
  441. reject();
  442. }
  443. }, type, quality);
  444. });
  445. } else {
  446. return dataUriToBlob(canvas.toDataURL(type, quality));
  447. }
  448. }
  449. function canvasToDataURL(canvas, type, quality) {
  450. type = type || 'image/png';
  451. return canvas.toDataURL(type, quality);
  452. }
  453. function blobToCanvas(blob) {
  454. return blobToImage(blob).then(function (image) {
  455. revokeImageUrl(image);
  456. var canvas = create(getWidth(image), getHeight(image));
  457. var context = get2dContext(canvas);
  458. context.drawImage(image, 0, 0);
  459. return canvas;
  460. });
  461. }
  462. function blobToDataUri(blob) {
  463. return new Promise(function (resolve) {
  464. var reader = new domGlobals.FileReader();
  465. reader.onloadend = function () {
  466. resolve(reader.result);
  467. };
  468. reader.readAsDataURL(blob);
  469. });
  470. }
  471. function revokeImageUrl(image) {
  472. domGlobals.URL.revokeObjectURL(image.src);
  473. }
  474. var blobToImage$1 = function (blob) {
  475. return blobToImage(blob);
  476. };
  477. var imageToBlob$1 = function (image) {
  478. return imageToBlob(image);
  479. };
  480. function create$1(getCanvas, blob, uri) {
  481. var initialType = blob.type;
  482. var getType = constant(initialType);
  483. function toBlob() {
  484. return Promise.resolve(blob);
  485. }
  486. function toDataURL() {
  487. return uri;
  488. }
  489. function toBase64() {
  490. return uri.split(',')[1];
  491. }
  492. function toAdjustedBlob(type, quality) {
  493. return getCanvas.then(function (canvas) {
  494. return canvasToBlob(canvas, type, quality);
  495. });
  496. }
  497. function toAdjustedDataURL(type, quality) {
  498. return getCanvas.then(function (canvas) {
  499. return canvasToDataURL(canvas, type, quality);
  500. });
  501. }
  502. function toAdjustedBase64(type, quality) {
  503. return toAdjustedDataURL(type, quality).then(function (dataurl) {
  504. return dataurl.split(',')[1];
  505. });
  506. }
  507. function toCanvas() {
  508. return getCanvas.then(clone);
  509. }
  510. return {
  511. getType: getType,
  512. toBlob: toBlob,
  513. toDataURL: toDataURL,
  514. toBase64: toBase64,
  515. toAdjustedBlob: toAdjustedBlob,
  516. toAdjustedDataURL: toAdjustedDataURL,
  517. toAdjustedBase64: toAdjustedBase64,
  518. toCanvas: toCanvas
  519. };
  520. }
  521. function fromBlob(blob) {
  522. return blobToDataUri(blob).then(function (uri) {
  523. return create$1(blobToCanvas(blob), blob, uri);
  524. });
  525. }
  526. function fromCanvas(canvas, type) {
  527. return canvasToBlob(canvas, type).then(function (blob) {
  528. return create$1(Promise.resolve(canvas), blob, canvas.toDataURL());
  529. });
  530. }
  531. function rotate(ir, angle) {
  532. return ir.toCanvas().then(function (canvas) {
  533. return applyRotate(canvas, ir.getType(), angle);
  534. });
  535. }
  536. function applyRotate(image, type, angle) {
  537. var canvas = create(image.width, image.height);
  538. var context = get2dContext(canvas);
  539. var translateX = 0;
  540. var translateY = 0;
  541. angle = angle < 0 ? 360 + angle : angle;
  542. if (angle === 90 || angle === 270) {
  543. resize(canvas, canvas.height, canvas.width);
  544. }
  545. if (angle === 90 || angle === 180) {
  546. translateX = canvas.width;
  547. }
  548. if (angle === 270 || angle === 180) {
  549. translateY = canvas.height;
  550. }
  551. context.translate(translateX, translateY);
  552. context.rotate(angle * Math.PI / 180);
  553. context.drawImage(image, 0, 0);
  554. return fromCanvas(canvas, type);
  555. }
  556. function flip(ir, axis) {
  557. return ir.toCanvas().then(function (canvas) {
  558. return applyFlip(canvas, ir.getType(), axis);
  559. });
  560. }
  561. function applyFlip(image, type, axis) {
  562. var canvas = create(image.width, image.height);
  563. var context = get2dContext(canvas);
  564. if (axis === 'v') {
  565. context.scale(1, -1);
  566. context.drawImage(image, 0, -canvas.height);
  567. } else {
  568. context.scale(-1, 1);
  569. context.drawImage(image, -canvas.width, 0);
  570. }
  571. return fromCanvas(canvas, type);
  572. }
  573. var flip$1 = function (ir, axis) {
  574. return flip(ir, axis);
  575. };
  576. var rotate$1 = function (ir, angle) {
  577. return rotate(ir, angle);
  578. };
  579. var blobToImageResult = function (blob) {
  580. return fromBlob(blob);
  581. };
  582. var global$2 = tinymce.util.Tools.resolve('tinymce.util.Delay');
  583. var global$3 = tinymce.util.Tools.resolve('tinymce.util.Promise');
  584. var global$4 = tinymce.util.Tools.resolve('tinymce.util.URI');
  585. var getToolbarItems = function (editor) {
  586. return editor.getParam('imagetools_toolbar', 'rotateleft rotateright flipv fliph editimage imageoptions');
  587. };
  588. var getProxyUrl = function (editor) {
  589. return editor.getParam('imagetools_proxy');
  590. };
  591. var getCorsHosts = function (editor) {
  592. return editor.getParam('imagetools_cors_hosts', [], 'string[]');
  593. };
  594. var getCredentialsHosts = function (editor) {
  595. return editor.getParam('imagetools_credentials_hosts', [], 'string[]');
  596. };
  597. var getFetchImage = function (editor) {
  598. return Option.from(editor.getParam('imagetools_fetch_image', null, 'function'));
  599. };
  600. var getApiKey = function (editor) {
  601. return editor.getParam('api_key', editor.getParam('imagetools_api_key', '', 'string'), 'string');
  602. };
  603. var getUploadTimeout = function (editor) {
  604. return editor.getParam('images_upload_timeout', 30000, 'number');
  605. };
  606. var shouldReuseFilename = function (editor) {
  607. return editor.getParam('images_reuse_filename', false, 'boolean');
  608. };
  609. function getImageSize(img) {
  610. var width, height;
  611. function isPxValue(value) {
  612. return /^[0-9\.]+px$/.test(value);
  613. }
  614. width = img.style.width;
  615. height = img.style.height;
  616. if (width || height) {
  617. if (isPxValue(width) && isPxValue(height)) {
  618. return {
  619. w: parseInt(width, 10),
  620. h: parseInt(height, 10)
  621. };
  622. }
  623. return null;
  624. }
  625. width = img.width;
  626. height = img.height;
  627. if (width && height) {
  628. return {
  629. w: parseInt(width, 10),
  630. h: parseInt(height, 10)
  631. };
  632. }
  633. return null;
  634. }
  635. function setImageSize(img, size) {
  636. var width, height;
  637. if (size) {
  638. width = img.style.width;
  639. height = img.style.height;
  640. if (width || height) {
  641. img.style.width = size.w + 'px';
  642. img.style.height = size.h + 'px';
  643. img.removeAttribute('data-mce-style');
  644. }
  645. width = img.width;
  646. height = img.height;
  647. if (width || height) {
  648. img.setAttribute('width', size.w);
  649. img.setAttribute('height', size.h);
  650. }
  651. }
  652. }
  653. function getNaturalImageSize(img) {
  654. return {
  655. w: img.naturalWidth,
  656. h: img.naturalHeight
  657. };
  658. }
  659. var ImageSize = {
  660. getImageSize: getImageSize,
  661. setImageSize: setImageSize,
  662. getNaturalImageSize: getNaturalImageSize
  663. };
  664. var typeOf = function (x) {
  665. if (x === null) {
  666. return 'null';
  667. }
  668. var t = typeof x;
  669. if (t === 'object' && (Array.prototype.isPrototypeOf(x) || x.constructor && x.constructor.name === 'Array')) {
  670. return 'array';
  671. }
  672. if (t === 'object' && (String.prototype.isPrototypeOf(x) || x.constructor && x.constructor.name === 'String')) {
  673. return 'string';
  674. }
  675. return t;
  676. };
  677. var isType = function (type) {
  678. return function (value) {
  679. return typeOf(value) === type;
  680. };
  681. };
  682. var isFunction = isType('function');
  683. var nativeSlice = Array.prototype.slice;
  684. var find = function (xs, pred) {
  685. for (var i = 0, len = xs.length; i < len; i++) {
  686. var x = xs[i];
  687. if (pred(x, i)) {
  688. return Option.some(x);
  689. }
  690. }
  691. return Option.none();
  692. };
  693. var from$1 = isFunction(Array.from) ? Array.from : function (x) {
  694. return nativeSlice.call(x);
  695. };
  696. var isValue = function (obj) {
  697. return obj !== null && obj !== undefined;
  698. };
  699. var traverse = function (json, path) {
  700. var value;
  701. value = path.reduce(function (result, key) {
  702. return isValue(result) ? result[key] : undefined;
  703. }, json);
  704. return isValue(value) ? value : null;
  705. };
  706. var requestUrlAsBlob = function (url, headers, withCredentials) {
  707. return new global$3(function (resolve) {
  708. var xhr;
  709. xhr = new domGlobals.XMLHttpRequest();
  710. xhr.onreadystatechange = function () {
  711. if (xhr.readyState === 4) {
  712. resolve({
  713. status: xhr.status,
  714. blob: this.response
  715. });
  716. }
  717. };
  718. xhr.open('GET', url, true);
  719. xhr.withCredentials = withCredentials;
  720. global$1.each(headers, function (value, key) {
  721. xhr.setRequestHeader(key, value);
  722. });
  723. xhr.responseType = 'blob';
  724. xhr.send();
  725. });
  726. };
  727. var readBlob = function (blob) {
  728. return new global$3(function (resolve) {
  729. var fr = new domGlobals.FileReader();
  730. fr.onload = function (e) {
  731. var data = e.target;
  732. resolve(data.result);
  733. };
  734. fr.readAsText(blob);
  735. });
  736. };
  737. var parseJson = function (text) {
  738. var json;
  739. try {
  740. json = JSON.parse(text);
  741. } catch (ex) {
  742. }
  743. return json;
  744. };
  745. var Utils = {
  746. traverse: traverse,
  747. readBlob: readBlob,
  748. requestUrlAsBlob: requestUrlAsBlob,
  749. parseJson: parseJson
  750. };
  751. var friendlyHttpErrors = [
  752. {
  753. code: 404,
  754. message: 'Could not find Image Proxy'
  755. },
  756. {
  757. code: 403,
  758. message: 'Rejected request'
  759. },
  760. {
  761. code: 0,
  762. message: 'Incorrect Image Proxy URL'
  763. }
  764. ];
  765. var friendlyServiceErrors = [
  766. {
  767. type: 'key_missing',
  768. message: 'The request did not include an api key.'
  769. },
  770. {
  771. type: 'key_not_found',
  772. message: 'The provided api key could not be found.'
  773. },
  774. {
  775. type: 'domain_not_trusted',
  776. message: 'The api key is not valid for the request origins.'
  777. }
  778. ];
  779. var isServiceErrorCode = function (code) {
  780. return code === 400 || code === 403 || code === 500;
  781. };
  782. var getHttpErrorMsg = function (status) {
  783. var message = find(friendlyHttpErrors, function (error) {
  784. return status === error.code;
  785. }).fold(constant('Unknown ImageProxy error'), function (error) {
  786. return error.message;
  787. });
  788. return 'ImageProxy HTTP error: ' + message;
  789. };
  790. var handleHttpError = function (status) {
  791. var message = getHttpErrorMsg(status);
  792. return global$3.reject(message);
  793. };
  794. var getServiceErrorMsg = function (type) {
  795. return find(friendlyServiceErrors, function (error) {
  796. return error.type === type;
  797. }).fold(constant('Unknown service error'), function (error) {
  798. return error.message;
  799. });
  800. };
  801. var getServiceError = function (text) {
  802. var serviceError = Utils.parseJson(text);
  803. var errorType = Utils.traverse(serviceError, [
  804. 'error',
  805. 'type'
  806. ]);
  807. var errorMsg = errorType ? getServiceErrorMsg(errorType) : 'Invalid JSON in service error message';
  808. return 'ImageProxy Service error: ' + errorMsg;
  809. };
  810. var handleServiceError = function (status, blob) {
  811. return Utils.readBlob(blob).then(function (text) {
  812. var serviceError = getServiceError(text);
  813. return global$3.reject(serviceError);
  814. });
  815. };
  816. var handleServiceErrorResponse = function (status, blob) {
  817. return isServiceErrorCode(status) ? handleServiceError(status, blob) : handleHttpError(status);
  818. };
  819. var Errors = {
  820. handleServiceErrorResponse: handleServiceErrorResponse,
  821. handleHttpError: handleHttpError,
  822. getHttpErrorMsg: getHttpErrorMsg,
  823. getServiceErrorMsg: getServiceErrorMsg
  824. };
  825. var appendApiKey = function (url, apiKey) {
  826. var separator = url.indexOf('?') === -1 ? '?' : '&';
  827. if (/[?&]apiKey=/.test(url) || !apiKey) {
  828. return url;
  829. } else {
  830. return url + separator + 'apiKey=' + encodeURIComponent(apiKey);
  831. }
  832. };
  833. var requestServiceBlob = function (url, apiKey) {
  834. var headers = {
  835. 'Content-Type': 'application/json;charset=UTF-8',
  836. 'tiny-api-key': apiKey
  837. };
  838. return Utils.requestUrlAsBlob(appendApiKey(url, apiKey), headers, false).then(function (result) {
  839. return result.status < 200 || result.status >= 300 ? Errors.handleServiceErrorResponse(result.status, result.blob) : global$3.resolve(result.blob);
  840. });
  841. };
  842. function requestBlob(url, withCredentials) {
  843. return Utils.requestUrlAsBlob(url, {}, withCredentials).then(function (result) {
  844. return result.status < 200 || result.status >= 300 ? Errors.handleHttpError(result.status) : global$3.resolve(result.blob);
  845. });
  846. }
  847. var getUrl = function (url, apiKey, withCredentials) {
  848. return apiKey ? requestServiceBlob(url, apiKey) : requestBlob(url, withCredentials);
  849. };
  850. var compareDocumentPosition = function (a, b, match) {
  851. return (a.compareDocumentPosition(b) & match) !== 0;
  852. };
  853. var documentPositionPreceding = function (a, b) {
  854. return compareDocumentPosition(a, b, domGlobals.Node.DOCUMENT_POSITION_PRECEDING);
  855. };
  856. var documentPositionContainedBy = function (a, b) {
  857. return compareDocumentPosition(a, b, domGlobals.Node.DOCUMENT_POSITION_CONTAINED_BY);
  858. };
  859. var Node = {
  860. documentPositionPreceding: documentPositionPreceding,
  861. documentPositionContainedBy: documentPositionContainedBy
  862. };
  863. var firstMatch = function (regexes, s) {
  864. for (var i = 0; i < regexes.length; i++) {
  865. var x = regexes[i];
  866. if (x.test(s)) {
  867. return x;
  868. }
  869. }
  870. return undefined;
  871. };
  872. var find$1 = function (regexes, agent) {
  873. var r = firstMatch(regexes, agent);
  874. if (!r) {
  875. return {
  876. major: 0,
  877. minor: 0
  878. };
  879. }
  880. var group = function (i) {
  881. return Number(agent.replace(r, '$' + i));
  882. };
  883. return nu(group(1), group(2));
  884. };
  885. var detect = function (versionRegexes, agent) {
  886. var cleanedAgent = String(agent).toLowerCase();
  887. if (versionRegexes.length === 0) {
  888. return unknown();
  889. }
  890. return find$1(versionRegexes, cleanedAgent);
  891. };
  892. var unknown = function () {
  893. return nu(0, 0);
  894. };
  895. var nu = function (major, minor) {
  896. return {
  897. major: major,
  898. minor: minor
  899. };
  900. };
  901. var Version = {
  902. nu: nu,
  903. detect: detect,
  904. unknown: unknown
  905. };
  906. var edge = 'Edge';
  907. var chrome = 'Chrome';
  908. var ie = 'IE';
  909. var opera = 'Opera';
  910. var firefox = 'Firefox';
  911. var safari = 'Safari';
  912. var isBrowser = function (name, current) {
  913. return function () {
  914. return current === name;
  915. };
  916. };
  917. var unknown$1 = function () {
  918. return nu$1({
  919. current: undefined,
  920. version: Version.unknown()
  921. });
  922. };
  923. var nu$1 = function (info) {
  924. var current = info.current;
  925. var version = info.version;
  926. return {
  927. current: current,
  928. version: version,
  929. isEdge: isBrowser(edge, current),
  930. isChrome: isBrowser(chrome, current),
  931. isIE: isBrowser(ie, current),
  932. isOpera: isBrowser(opera, current),
  933. isFirefox: isBrowser(firefox, current),
  934. isSafari: isBrowser(safari, current)
  935. };
  936. };
  937. var Browser = {
  938. unknown: unknown$1,
  939. nu: nu$1,
  940. edge: constant(edge),
  941. chrome: constant(chrome),
  942. ie: constant(ie),
  943. opera: constant(opera),
  944. firefox: constant(firefox),
  945. safari: constant(safari)
  946. };
  947. var windows = 'Windows';
  948. var ios = 'iOS';
  949. var android = 'Android';
  950. var linux = 'Linux';
  951. var osx = 'OSX';
  952. var solaris = 'Solaris';
  953. var freebsd = 'FreeBSD';
  954. var isOS = function (name, current) {
  955. return function () {
  956. return current === name;
  957. };
  958. };
  959. var unknown$2 = function () {
  960. return nu$2({
  961. current: undefined,
  962. version: Version.unknown()
  963. });
  964. };
  965. var nu$2 = function (info) {
  966. var current = info.current;
  967. var version = info.version;
  968. return {
  969. current: current,
  970. version: version,
  971. isWindows: isOS(windows, current),
  972. isiOS: isOS(ios, current),
  973. isAndroid: isOS(android, current),
  974. isOSX: isOS(osx, current),
  975. isLinux: isOS(linux, current),
  976. isSolaris: isOS(solaris, current),
  977. isFreeBSD: isOS(freebsd, current)
  978. };
  979. };
  980. var OperatingSystem = {
  981. unknown: unknown$2,
  982. nu: nu$2,
  983. windows: constant(windows),
  984. ios: constant(ios),
  985. android: constant(android),
  986. linux: constant(linux),
  987. osx: constant(osx),
  988. solaris: constant(solaris),
  989. freebsd: constant(freebsd)
  990. };
  991. var DeviceType = function (os, browser, userAgent, mediaMatch) {
  992. var isiPad = os.isiOS() && /ipad/i.test(userAgent) === true;
  993. var isiPhone = os.isiOS() && !isiPad;
  994. var isMobile = os.isiOS() || os.isAndroid();
  995. var isTouch = isMobile || mediaMatch('(pointer:coarse)');
  996. var isTablet = isiPad || !isiPhone && isMobile && mediaMatch('(min-device-width:768px)');
  997. var isPhone = isiPhone || isMobile && !isTablet;
  998. var iOSwebview = browser.isSafari() && os.isiOS() && /safari/i.test(userAgent) === false;
  999. var isDesktop = !isPhone && !isTablet && !iOSwebview;
  1000. return {
  1001. isiPad: constant(isiPad),
  1002. isiPhone: constant(isiPhone),
  1003. isTablet: constant(isTablet),
  1004. isPhone: constant(isPhone),
  1005. isTouch: constant(isTouch),
  1006. isAndroid: os.isAndroid,
  1007. isiOS: os.isiOS,
  1008. isWebView: constant(iOSwebview),
  1009. isDesktop: constant(isDesktop)
  1010. };
  1011. };
  1012. var detect$1 = function (candidates, userAgent) {
  1013. var agent = String(userAgent).toLowerCase();
  1014. return find(candidates, function (candidate) {
  1015. return candidate.search(agent);
  1016. });
  1017. };
  1018. var detectBrowser = function (browsers, userAgent) {
  1019. return detect$1(browsers, userAgent).map(function (browser) {
  1020. var version = Version.detect(browser.versionRegexes, userAgent);
  1021. return {
  1022. current: browser.name,
  1023. version: version
  1024. };
  1025. });
  1026. };
  1027. var detectOs = function (oses, userAgent) {
  1028. return detect$1(oses, userAgent).map(function (os) {
  1029. var version = Version.detect(os.versionRegexes, userAgent);
  1030. return {
  1031. current: os.name,
  1032. version: version
  1033. };
  1034. });
  1035. };
  1036. var UaString = {
  1037. detectBrowser: detectBrowser,
  1038. detectOs: detectOs
  1039. };
  1040. var contains = function (str, substr) {
  1041. return str.indexOf(substr) !== -1;
  1042. };
  1043. var normalVersionRegex = /.*?version\/\ ?([0-9]+)\.([0-9]+).*/;
  1044. var checkContains = function (target) {
  1045. return function (uastring) {
  1046. return contains(uastring, target);
  1047. };
  1048. };
  1049. var browsers = [
  1050. {
  1051. name: 'Edge',
  1052. versionRegexes: [/.*?edge\/ ?([0-9]+)\.([0-9]+)$/],
  1053. search: function (uastring) {
  1054. return contains(uastring, 'edge/') && contains(uastring, 'chrome') && contains(uastring, 'safari') && contains(uastring, 'applewebkit');
  1055. }
  1056. },
  1057. {
  1058. name: 'Chrome',
  1059. versionRegexes: [
  1060. /.*?chrome\/([0-9]+)\.([0-9]+).*/,
  1061. normalVersionRegex
  1062. ],
  1063. search: function (uastring) {
  1064. return contains(uastring, 'chrome') && !contains(uastring, 'chromeframe');
  1065. }
  1066. },
  1067. {
  1068. name: 'IE',
  1069. versionRegexes: [
  1070. /.*?msie\ ?([0-9]+)\.([0-9]+).*/,
  1071. /.*?rv:([0-9]+)\.([0-9]+).*/
  1072. ],
  1073. search: function (uastring) {
  1074. return contains(uastring, 'msie') || contains(uastring, 'trident');
  1075. }
  1076. },
  1077. {
  1078. name: 'Opera',
  1079. versionRegexes: [
  1080. normalVersionRegex,
  1081. /.*?opera\/([0-9]+)\.([0-9]+).*/
  1082. ],
  1083. search: checkContains('opera')
  1084. },
  1085. {
  1086. name: 'Firefox',
  1087. versionRegexes: [/.*?firefox\/\ ?([0-9]+)\.([0-9]+).*/],
  1088. search: checkContains('firefox')
  1089. },
  1090. {
  1091. name: 'Safari',
  1092. versionRegexes: [
  1093. normalVersionRegex,
  1094. /.*?cpu os ([0-9]+)_([0-9]+).*/
  1095. ],
  1096. search: function (uastring) {
  1097. return (contains(uastring, 'safari') || contains(uastring, 'mobile/')) && contains(uastring, 'applewebkit');
  1098. }
  1099. }
  1100. ];
  1101. var oses = [
  1102. {
  1103. name: 'Windows',
  1104. search: checkContains('win'),
  1105. versionRegexes: [/.*?windows\ nt\ ?([0-9]+)\.([0-9]+).*/]
  1106. },
  1107. {
  1108. name: 'iOS',
  1109. search: function (uastring) {
  1110. return contains(uastring, 'iphone') || contains(uastring, 'ipad');
  1111. },
  1112. versionRegexes: [
  1113. /.*?version\/\ ?([0-9]+)\.([0-9]+).*/,
  1114. /.*cpu os ([0-9]+)_([0-9]+).*/,
  1115. /.*cpu iphone os ([0-9]+)_([0-9]+).*/
  1116. ]
  1117. },
  1118. {
  1119. name: 'Android',
  1120. search: checkContains('android'),
  1121. versionRegexes: [/.*?android\ ?([0-9]+)\.([0-9]+).*/]
  1122. },
  1123. {
  1124. name: 'OSX',
  1125. search: checkContains('os x'),
  1126. versionRegexes: [/.*?os\ x\ ?([0-9]+)_([0-9]+).*/]
  1127. },
  1128. {
  1129. name: 'Linux',
  1130. search: checkContains('linux'),
  1131. versionRegexes: []
  1132. },
  1133. {
  1134. name: 'Solaris',
  1135. search: checkContains('sunos'),
  1136. versionRegexes: []
  1137. },
  1138. {
  1139. name: 'FreeBSD',
  1140. search: checkContains('freebsd'),
  1141. versionRegexes: []
  1142. }
  1143. ];
  1144. var PlatformInfo = {
  1145. browsers: constant(browsers),
  1146. oses: constant(oses)
  1147. };
  1148. var detect$2 = function (userAgent, mediaMatch) {
  1149. var browsers = PlatformInfo.browsers();
  1150. var oses = PlatformInfo.oses();
  1151. var browser = UaString.detectBrowser(browsers, userAgent).fold(Browser.unknown, Browser.nu);
  1152. var os = UaString.detectOs(oses, userAgent).fold(OperatingSystem.unknown, OperatingSystem.nu);
  1153. var deviceType = DeviceType(os, browser, userAgent, mediaMatch);
  1154. return {
  1155. browser: browser,
  1156. os: os,
  1157. deviceType: deviceType
  1158. };
  1159. };
  1160. var PlatformDetection = { detect: detect$2 };
  1161. var mediaMatch = function (query) {
  1162. return domGlobals.window.matchMedia(query).matches;
  1163. };
  1164. var platform = Cell(PlatformDetection.detect(domGlobals.navigator.userAgent, mediaMatch));
  1165. var detect$3 = function () {
  1166. return platform.get();
  1167. };
  1168. var fromHtml = function (html, scope) {
  1169. var doc = scope || domGlobals.document;
  1170. var div = doc.createElement('div');
  1171. div.innerHTML = html;
  1172. if (!div.hasChildNodes() || div.childNodes.length > 1) {
  1173. domGlobals.console.error('HTML does not have a single root node', html);
  1174. throw new Error('HTML must have a single root node');
  1175. }
  1176. return fromDom(div.childNodes[0]);
  1177. };
  1178. var fromTag = function (tag, scope) {
  1179. var doc = scope || domGlobals.document;
  1180. var node = doc.createElement(tag);
  1181. return fromDom(node);
  1182. };
  1183. var fromText = function (text, scope) {
  1184. var doc = scope || domGlobals.document;
  1185. var node = doc.createTextNode(text);
  1186. return fromDom(node);
  1187. };
  1188. var fromDom = function (node) {
  1189. if (node === null || node === undefined) {
  1190. throw new Error('Node cannot be null or undefined');
  1191. }
  1192. return { dom: constant(node) };
  1193. };
  1194. var fromPoint = function (docElm, x, y) {
  1195. var doc = docElm.dom();
  1196. return Option.from(doc.elementFromPoint(x, y)).map(fromDom);
  1197. };
  1198. var Element = {
  1199. fromHtml: fromHtml,
  1200. fromTag: fromTag,
  1201. fromText: fromText,
  1202. fromDom: fromDom,
  1203. fromPoint: fromPoint
  1204. };
  1205. var ATTRIBUTE = domGlobals.Node.ATTRIBUTE_NODE;
  1206. var CDATA_SECTION = domGlobals.Node.CDATA_SECTION_NODE;
  1207. var COMMENT = domGlobals.Node.COMMENT_NODE;
  1208. var DOCUMENT = domGlobals.Node.DOCUMENT_NODE;
  1209. var DOCUMENT_TYPE = domGlobals.Node.DOCUMENT_TYPE_NODE;
  1210. var DOCUMENT_FRAGMENT = domGlobals.Node.DOCUMENT_FRAGMENT_NODE;
  1211. var ELEMENT = domGlobals.Node.ELEMENT_NODE;
  1212. var TEXT = domGlobals.Node.TEXT_NODE;
  1213. var PROCESSING_INSTRUCTION = domGlobals.Node.PROCESSING_INSTRUCTION_NODE;
  1214. var ENTITY_REFERENCE = domGlobals.Node.ENTITY_REFERENCE_NODE;
  1215. var ENTITY = domGlobals.Node.ENTITY_NODE;
  1216. var NOTATION = domGlobals.Node.NOTATION_NODE;
  1217. var ELEMENT$1 = ELEMENT;
  1218. var is = function (element, selector) {
  1219. var dom = element.dom();
  1220. if (dom.nodeType !== ELEMENT$1) {
  1221. return false;
  1222. } else {
  1223. var elem = dom;
  1224. if (elem.matches !== undefined) {
  1225. return elem.matches(selector);
  1226. } else if (elem.msMatchesSelector !== undefined) {
  1227. return elem.msMatchesSelector(selector);
  1228. } else if (elem.webkitMatchesSelector !== undefined) {
  1229. return elem.webkitMatchesSelector(selector);
  1230. } else if (elem.mozMatchesSelector !== undefined) {
  1231. return elem.mozMatchesSelector(selector);
  1232. } else {
  1233. throw new Error('Browser lacks native selectors');
  1234. }
  1235. }
  1236. };
  1237. var regularContains = function (e1, e2) {
  1238. var d1 = e1.dom();
  1239. var d2 = e2.dom();
  1240. return d1 === d2 ? false : d1.contains(d2);
  1241. };
  1242. var ieContains = function (e1, e2) {
  1243. return Node.documentPositionContainedBy(e1.dom(), e2.dom());
  1244. };
  1245. var browser = detect$3().browser;
  1246. var contains$1 = browser.isIE() ? ieContains : regularContains;
  1247. var Global = typeof domGlobals.window !== 'undefined' ? domGlobals.window : Function('return this;')();
  1248. var child = function (scope, predicate) {
  1249. var pred = function (node) {
  1250. return predicate(Element.fromDom(node));
  1251. };
  1252. var result = find(scope.dom().childNodes, pred);
  1253. return result.map(Element.fromDom);
  1254. };
  1255. var child$1 = function (scope, selector) {
  1256. return child(scope, function (e) {
  1257. return is(e, selector);
  1258. });
  1259. };
  1260. var count = 0;
  1261. var getFigureImg = function (elem) {
  1262. return child$1(Element.fromDom(elem), 'img');
  1263. };
  1264. var isFigure = function (editor, elem) {
  1265. return editor.dom.is(elem, 'figure');
  1266. };
  1267. var getEditableImage = function (editor, elem) {
  1268. var isImage = function (imgNode) {
  1269. return editor.dom.is(imgNode, 'img:not([data-mce-object],[data-mce-placeholder])');
  1270. };
  1271. var isEditable = function (imgNode) {
  1272. return isImage(imgNode) && (isLocalImage(editor, imgNode) || isCorsImage(editor, imgNode) || editor.settings.imagetools_proxy);
  1273. };
  1274. if (isFigure(editor, elem)) {
  1275. var imgOpt = getFigureImg(elem);
  1276. return imgOpt.map(function (img) {
  1277. return isEditable(img.dom()) ? Option.some(img.dom()) : Option.none();
  1278. });
  1279. }
  1280. return isEditable(elem) ? Option.some(elem) : Option.none();
  1281. };
  1282. var displayError = function (editor, error) {
  1283. editor.notificationManager.open({
  1284. text: error,
  1285. type: 'error'
  1286. });
  1287. };
  1288. var getSelectedImage = function (editor) {
  1289. var elem = editor.selection.getNode();
  1290. if (isFigure(editor, elem)) {
  1291. return getFigureImg(elem);
  1292. } else {
  1293. return Option.some(Element.fromDom(elem));
  1294. }
  1295. };
  1296. var extractFilename = function (editor, url) {
  1297. var m = url.match(/\/([^\/\?]+)?\.(?:jpeg|jpg|png|gif)(?:\?|$)/i);
  1298. if (m) {
  1299. return editor.dom.encode(m[1]);
  1300. }
  1301. return null;
  1302. };
  1303. var createId = function () {
  1304. return 'imagetools' + count++;
  1305. };
  1306. var isLocalImage = function (editor, img) {
  1307. var url = img.src;
  1308. return url.indexOf('data:') === 0 || url.indexOf('blob:') === 0 || new global$4(url).host === editor.documentBaseURI.host;
  1309. };
  1310. var isCorsImage = function (editor, img) {
  1311. return global$1.inArray(getCorsHosts(editor), new global$4(img.src).host) !== -1;
  1312. };
  1313. var isCorsWithCredentialsImage = function (editor, img) {
  1314. return global$1.inArray(getCredentialsHosts(editor), new global$4(img.src).host) !== -1;
  1315. };
  1316. var defaultFetchImage = function (editor, img) {
  1317. var src = img.src, apiKey;
  1318. if (isCorsImage(editor, img)) {
  1319. return getUrl(img.src, null, isCorsWithCredentialsImage(editor, img));
  1320. }
  1321. if (!isLocalImage(editor, img)) {
  1322. src = getProxyUrl(editor);
  1323. src += (src.indexOf('?') === -1 ? '?' : '&') + 'url=' + encodeURIComponent(img.src);
  1324. apiKey = getApiKey(editor);
  1325. return getUrl(src, apiKey, false);
  1326. }
  1327. return imageToBlob$1(img);
  1328. };
  1329. var imageToBlob$2 = function (editor, img) {
  1330. return getFetchImage(editor).fold(function () {
  1331. return defaultFetchImage(editor, img);
  1332. }, function (customFetchImage) {
  1333. return customFetchImage(img);
  1334. });
  1335. };
  1336. var findBlob = function (editor, img) {
  1337. var blobInfo;
  1338. blobInfo = editor.editorUpload.blobCache.getByUri(img.src);
  1339. if (blobInfo) {
  1340. return global$3.resolve(blobInfo.blob());
  1341. }
  1342. return imageToBlob$2(editor, img);
  1343. };
  1344. var startTimedUpload = function (editor, imageUploadTimerState) {
  1345. var imageUploadTimer = global$2.setEditorTimeout(editor, function () {
  1346. editor.editorUpload.uploadImagesAuto();
  1347. }, getUploadTimeout(editor));
  1348. imageUploadTimerState.set(imageUploadTimer);
  1349. };
  1350. var cancelTimedUpload = function (imageUploadTimerState) {
  1351. global$2.clearTimeout(imageUploadTimerState.get());
  1352. };
  1353. var updateSelectedImage = function (editor, ir, uploadImmediately, imageUploadTimerState, selectedImage, size) {
  1354. return ir.toBlob().then(function (blob) {
  1355. var uri, name, blobCache, blobInfo;
  1356. blobCache = editor.editorUpload.blobCache;
  1357. uri = selectedImage.src;
  1358. if (shouldReuseFilename(editor)) {
  1359. blobInfo = blobCache.getByUri(uri);
  1360. if (blobInfo) {
  1361. uri = blobInfo.uri();
  1362. name = blobInfo.name();
  1363. } else {
  1364. name = extractFilename(editor, uri);
  1365. }
  1366. }
  1367. blobInfo = blobCache.create({
  1368. id: createId(),
  1369. blob: blob,
  1370. base64: ir.toBase64(),
  1371. uri: uri,
  1372. name: name
  1373. });
  1374. blobCache.add(blobInfo);
  1375. editor.undoManager.transact(function () {
  1376. function imageLoadedHandler() {
  1377. editor.$(selectedImage).off('load', imageLoadedHandler);
  1378. editor.nodeChanged();
  1379. if (uploadImmediately) {
  1380. editor.editorUpload.uploadImagesAuto();
  1381. } else {
  1382. cancelTimedUpload(imageUploadTimerState);
  1383. startTimedUpload(editor, imageUploadTimerState);
  1384. }
  1385. }
  1386. editor.$(selectedImage).on('load', imageLoadedHandler);
  1387. if (size) {
  1388. editor.$(selectedImage).attr({
  1389. width: size.w,
  1390. height: size.h
  1391. });
  1392. }
  1393. editor.$(selectedImage).attr({ src: blobInfo.blobUri() }).removeAttr('data-mce-src');
  1394. });
  1395. return blobInfo;
  1396. });
  1397. };
  1398. var selectedImageOperation = function (editor, imageUploadTimerState, fn, size) {
  1399. return function () {
  1400. var imgOpt = getSelectedImage(editor);
  1401. return imgOpt.fold(function () {
  1402. displayError(editor, 'Could not find selected image');
  1403. }, function (img) {
  1404. return editor._scanForImages().then(function () {
  1405. return findBlob(editor, img.dom());
  1406. }).then(blobToImageResult).then(fn).then(function (imageResult) {
  1407. return updateSelectedImage(editor, imageResult, false, imageUploadTimerState, img.dom(), size);
  1408. }, function (error) {
  1409. displayError(editor, error);
  1410. });
  1411. });
  1412. };
  1413. };
  1414. var rotate$2 = function (editor, imageUploadTimerState, angle) {
  1415. return function () {
  1416. var imgOpt = getSelectedImage(editor);
  1417. var flippedSize = imgOpt.fold(function () {
  1418. return null;
  1419. }, function (img) {
  1420. var size = ImageSize.getImageSize(img.dom());
  1421. return size ? {
  1422. w: size.h,
  1423. h: size.w
  1424. } : null;
  1425. });
  1426. return selectedImageOperation(editor, imageUploadTimerState, function (imageResult) {
  1427. return rotate$1(imageResult, angle);
  1428. }, flippedSize)();
  1429. };
  1430. };
  1431. var flip$2 = function (editor, imageUploadTimerState, axis) {
  1432. return function () {
  1433. return selectedImageOperation(editor, imageUploadTimerState, function (imageResult) {
  1434. return flip$1(imageResult, axis);
  1435. })();
  1436. };
  1437. };
  1438. var handleDialogBlob = function (editor, imageUploadTimerState, img, originalSize, blob) {
  1439. return new global$3(function (resolve) {
  1440. blobToImage$1(blob).then(function (newImage) {
  1441. var newSize = ImageSize.getNaturalImageSize(newImage);
  1442. if (originalSize.w !== newSize.w || originalSize.h !== newSize.h) {
  1443. if (ImageSize.getImageSize(img)) {
  1444. ImageSize.setImageSize(img, newSize);
  1445. }
  1446. }
  1447. domGlobals.URL.revokeObjectURL(newImage.src);
  1448. return blob;
  1449. }).then(blobToImageResult).then(function (imageResult) {
  1450. return updateSelectedImage(editor, imageResult, true, imageUploadTimerState, img);
  1451. }, function () {
  1452. });
  1453. });
  1454. };
  1455. var Actions = {
  1456. rotate: rotate$2,
  1457. flip: flip$2,
  1458. getEditableImage: getEditableImage,
  1459. cancelTimedUpload: cancelTimedUpload,
  1460. findBlob: findBlob,
  1461. getSelectedImage: getSelectedImage,
  1462. handleDialogBlob: handleDialogBlob
  1463. };
  1464. var saveState = constant('save-state');
  1465. var disable = constant('disable');
  1466. var enable = constant('enable');
  1467. var createState = function (blob) {
  1468. return {
  1469. blob: blob,
  1470. url: domGlobals.URL.createObjectURL(blob)
  1471. };
  1472. };
  1473. var makeOpen = function (editor, imageUploadTimerState) {
  1474. return function () {
  1475. var getLoadedSpec = function (currentState) {
  1476. return {
  1477. title: 'Edit Image',
  1478. size: 'large',
  1479. body: {
  1480. type: 'panel',
  1481. items: [{
  1482. type: 'imagetools',
  1483. name: 'imagetools',
  1484. label: 'Edit Image',
  1485. currentState: currentState
  1486. }]
  1487. },
  1488. buttons: [
  1489. {
  1490. type: 'cancel',
  1491. name: 'cancel',
  1492. text: 'Cancel'
  1493. },
  1494. {
  1495. type: 'submit',
  1496. name: 'save',
  1497. text: 'Save',
  1498. primary: true,
  1499. disabled: true
  1500. }
  1501. ],
  1502. onSubmit: function (api) {
  1503. var blob = api.getData().imagetools.blob;
  1504. originalImgOpt.each(function (originalImg) {
  1505. originalSizeOpt.each(function (originalSize) {
  1506. Actions.handleDialogBlob(editor, imageUploadTimerState, originalImg.dom(), originalSize, blob);
  1507. });
  1508. });
  1509. api.close();
  1510. },
  1511. onCancel: function () {
  1512. },
  1513. onAction: function (api, details) {
  1514. switch (details.name) {
  1515. case saveState():
  1516. if (details.value) {
  1517. api.enable('save');
  1518. } else {
  1519. api.disable('save');
  1520. }
  1521. break;
  1522. case disable():
  1523. api.disable('save');
  1524. api.disable('cancel');
  1525. break;
  1526. case enable():
  1527. api.enable('cancel');
  1528. break;
  1529. }
  1530. }
  1531. };
  1532. };
  1533. var originalImgOpt = Actions.getSelectedImage(editor);
  1534. var originalSizeOpt = originalImgOpt.map(function (origImg) {
  1535. return ImageSize.getNaturalImageSize(origImg.dom());
  1536. });
  1537. var imgOpt = Actions.getSelectedImage(editor);
  1538. imgOpt.each(function (img) {
  1539. Actions.getEditableImage(editor, img.dom()).each(function (_) {
  1540. Actions.findBlob(editor, img.dom()).then(function (blob) {
  1541. var state = createState(blob);
  1542. editor.windowManager.open(getLoadedSpec(state));
  1543. });
  1544. });
  1545. });
  1546. };
  1547. };
  1548. var Dialog = { makeOpen: makeOpen };
  1549. var register = function (editor, imageUploadTimerState) {
  1550. global$1.each({
  1551. mceImageRotateLeft: Actions.rotate(editor, imageUploadTimerState, -90),
  1552. mceImageRotateRight: Actions.rotate(editor, imageUploadTimerState, 90),
  1553. mceImageFlipVertical: Actions.flip(editor, imageUploadTimerState, 'v'),
  1554. mceImageFlipHorizontal: Actions.flip(editor, imageUploadTimerState, 'h'),
  1555. mceEditImage: Dialog.makeOpen(editor, imageUploadTimerState)
  1556. }, function (fn, cmd) {
  1557. editor.addCommand(cmd, fn);
  1558. });
  1559. };
  1560. var Commands = { register: register };
  1561. var setup = function (editor, imageUploadTimerState, lastSelectedImageState) {
  1562. editor.on('NodeChange', function (e) {
  1563. var lastSelectedImage = lastSelectedImageState.get();
  1564. if (lastSelectedImage && lastSelectedImage.src !== e.element.src) {
  1565. Actions.cancelTimedUpload(imageUploadTimerState);
  1566. editor.editorUpload.uploadImagesAuto();
  1567. lastSelectedImageState.set(null);
  1568. }
  1569. Actions.getEditableImage(editor, e.element).each(lastSelectedImageState.set);
  1570. });
  1571. };
  1572. var UploadSelectedImage = { setup: setup };
  1573. var register$1 = function (editor) {
  1574. var cmd = function (command) {
  1575. return function () {
  1576. return editor.execCommand(command);
  1577. };
  1578. };
  1579. editor.ui.registry.addButton('rotateleft', {
  1580. tooltip: 'Rotate counterclockwise',
  1581. icon: 'rotate-left',
  1582. onAction: cmd('mceImageRotateLeft')
  1583. });
  1584. editor.ui.registry.addButton('rotateright', {
  1585. tooltip: 'Rotate clockwise',
  1586. icon: 'rotate-right',
  1587. onAction: cmd('mceImageRotateRight')
  1588. });
  1589. editor.ui.registry.addButton('flipv', {
  1590. tooltip: 'Flip vertically',
  1591. icon: 'flip-vertically',
  1592. onAction: cmd('mceImageFlipVertical')
  1593. });
  1594. editor.ui.registry.addButton('fliph', {
  1595. tooltip: 'Flip horizontally',
  1596. icon: 'flip-horizontally',
  1597. onAction: cmd('mceImageFlipHorizontal')
  1598. });
  1599. editor.ui.registry.addButton('editimage', {
  1600. tooltip: 'Edit image',
  1601. icon: 'edit-image',
  1602. onAction: cmd('mceEditImage'),
  1603. onSetup: function (buttonApi) {
  1604. var setDisabled = function () {
  1605. var elementOpt = Actions.getSelectedImage(editor);
  1606. elementOpt.each(function (element) {
  1607. var disabled = Actions.getEditableImage(editor, element.dom()).isNone();
  1608. buttonApi.setDisabled(disabled);
  1609. });
  1610. };
  1611. editor.on('NodeChange', setDisabled);
  1612. return function () {
  1613. editor.off('NodeChange', setDisabled);
  1614. };
  1615. }
  1616. });
  1617. editor.ui.registry.addButton('imageoptions', {
  1618. tooltip: 'Image options',
  1619. icon: 'image-options',
  1620. onAction: cmd('mceImage')
  1621. });
  1622. editor.ui.registry.addContextMenu('imagetools', {
  1623. update: function (element) {
  1624. return Actions.getEditableImage(editor, element).fold(function () {
  1625. return [];
  1626. }, function (_) {
  1627. return [{
  1628. text: 'Edit image',
  1629. icon: 'edit-image',
  1630. onAction: cmd('mceEditImage')
  1631. }];
  1632. });
  1633. }
  1634. });
  1635. };
  1636. var Buttons = { register: register$1 };
  1637. var register$2 = function (editor) {
  1638. editor.ui.registry.addContextToolbar('imagetools', {
  1639. items: getToolbarItems(editor),
  1640. predicate: function (elem) {
  1641. return Actions.getEditableImage(editor, elem).isSome();
  1642. },
  1643. position: 'node',
  1644. scope: 'node'
  1645. });
  1646. };
  1647. var ContextToolbar = { register: register$2 };
  1648. function Plugin () {
  1649. global.add('imagetools', function (editor) {
  1650. var imageUploadTimerState = Cell(0);
  1651. var lastSelectedImageState = Cell(null);
  1652. Commands.register(editor, imageUploadTimerState);
  1653. Buttons.register(editor);
  1654. ContextToolbar.register(editor);
  1655. UploadSelectedImage.setup(editor, imageUploadTimerState, lastSelectedImageState);
  1656. });
  1657. }
  1658. Plugin();
  1659. }(window));