plugin.js 53 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718
  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.2.0 (2020-02-13)
  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 chromeos = 'ChromeOS';
  955. var isOS = function (name, current) {
  956. return function () {
  957. return current === name;
  958. };
  959. };
  960. var unknown$2 = function () {
  961. return nu$2({
  962. current: undefined,
  963. version: Version.unknown()
  964. });
  965. };
  966. var nu$2 = function (info) {
  967. var current = info.current;
  968. var version = info.version;
  969. return {
  970. current: current,
  971. version: version,
  972. isWindows: isOS(windows, current),
  973. isiOS: isOS(ios, current),
  974. isAndroid: isOS(android, current),
  975. isOSX: isOS(osx, current),
  976. isLinux: isOS(linux, current),
  977. isSolaris: isOS(solaris, current),
  978. isFreeBSD: isOS(freebsd, current),
  979. isChromeOS: isOS(chromeos, current)
  980. };
  981. };
  982. var OperatingSystem = {
  983. unknown: unknown$2,
  984. nu: nu$2,
  985. windows: constant(windows),
  986. ios: constant(ios),
  987. android: constant(android),
  988. linux: constant(linux),
  989. osx: constant(osx),
  990. solaris: constant(solaris),
  991. freebsd: constant(freebsd),
  992. chromeos: constant(chromeos)
  993. };
  994. var DeviceType = function (os, browser, userAgent, mediaMatch) {
  995. var isiPad = os.isiOS() && /ipad/i.test(userAgent) === true;
  996. var isiPhone = os.isiOS() && !isiPad;
  997. var isMobile = os.isiOS() || os.isAndroid();
  998. var isTouch = isMobile || mediaMatch('(pointer:coarse)');
  999. var isTablet = isiPad || !isiPhone && isMobile && mediaMatch('(min-device-width:768px)');
  1000. var isPhone = isiPhone || isMobile && !isTablet;
  1001. var iOSwebview = browser.isSafari() && os.isiOS() && /safari/i.test(userAgent) === false;
  1002. var isDesktop = !isPhone && !isTablet && !iOSwebview;
  1003. return {
  1004. isiPad: constant(isiPad),
  1005. isiPhone: constant(isiPhone),
  1006. isTablet: constant(isTablet),
  1007. isPhone: constant(isPhone),
  1008. isTouch: constant(isTouch),
  1009. isAndroid: os.isAndroid,
  1010. isiOS: os.isiOS,
  1011. isWebView: constant(iOSwebview),
  1012. isDesktop: constant(isDesktop)
  1013. };
  1014. };
  1015. var detect$1 = function (candidates, userAgent) {
  1016. var agent = String(userAgent).toLowerCase();
  1017. return find(candidates, function (candidate) {
  1018. return candidate.search(agent);
  1019. });
  1020. };
  1021. var detectBrowser = function (browsers, userAgent) {
  1022. return detect$1(browsers, userAgent).map(function (browser) {
  1023. var version = Version.detect(browser.versionRegexes, userAgent);
  1024. return {
  1025. current: browser.name,
  1026. version: version
  1027. };
  1028. });
  1029. };
  1030. var detectOs = function (oses, userAgent) {
  1031. return detect$1(oses, userAgent).map(function (os) {
  1032. var version = Version.detect(os.versionRegexes, userAgent);
  1033. return {
  1034. current: os.name,
  1035. version: version
  1036. };
  1037. });
  1038. };
  1039. var UaString = {
  1040. detectBrowser: detectBrowser,
  1041. detectOs: detectOs
  1042. };
  1043. var contains = function (str, substr) {
  1044. return str.indexOf(substr) !== -1;
  1045. };
  1046. var normalVersionRegex = /.*?version\/\ ?([0-9]+)\.([0-9]+).*/;
  1047. var checkContains = function (target) {
  1048. return function (uastring) {
  1049. return contains(uastring, target);
  1050. };
  1051. };
  1052. var browsers = [
  1053. {
  1054. name: 'Edge',
  1055. versionRegexes: [/.*?edge\/ ?([0-9]+)\.([0-9]+)$/],
  1056. search: function (uastring) {
  1057. return contains(uastring, 'edge/') && contains(uastring, 'chrome') && contains(uastring, 'safari') && contains(uastring, 'applewebkit');
  1058. }
  1059. },
  1060. {
  1061. name: 'Chrome',
  1062. versionRegexes: [
  1063. /.*?chrome\/([0-9]+)\.([0-9]+).*/,
  1064. normalVersionRegex
  1065. ],
  1066. search: function (uastring) {
  1067. return contains(uastring, 'chrome') && !contains(uastring, 'chromeframe');
  1068. }
  1069. },
  1070. {
  1071. name: 'IE',
  1072. versionRegexes: [
  1073. /.*?msie\ ?([0-9]+)\.([0-9]+).*/,
  1074. /.*?rv:([0-9]+)\.([0-9]+).*/
  1075. ],
  1076. search: function (uastring) {
  1077. return contains(uastring, 'msie') || contains(uastring, 'trident');
  1078. }
  1079. },
  1080. {
  1081. name: 'Opera',
  1082. versionRegexes: [
  1083. normalVersionRegex,
  1084. /.*?opera\/([0-9]+)\.([0-9]+).*/
  1085. ],
  1086. search: checkContains('opera')
  1087. },
  1088. {
  1089. name: 'Firefox',
  1090. versionRegexes: [/.*?firefox\/\ ?([0-9]+)\.([0-9]+).*/],
  1091. search: checkContains('firefox')
  1092. },
  1093. {
  1094. name: 'Safari',
  1095. versionRegexes: [
  1096. normalVersionRegex,
  1097. /.*?cpu os ([0-9]+)_([0-9]+).*/
  1098. ],
  1099. search: function (uastring) {
  1100. return (contains(uastring, 'safari') || contains(uastring, 'mobile/')) && contains(uastring, 'applewebkit');
  1101. }
  1102. }
  1103. ];
  1104. var oses = [
  1105. {
  1106. name: 'Windows',
  1107. search: checkContains('win'),
  1108. versionRegexes: [/.*?windows\ nt\ ?([0-9]+)\.([0-9]+).*/]
  1109. },
  1110. {
  1111. name: 'iOS',
  1112. search: function (uastring) {
  1113. return contains(uastring, 'iphone') || contains(uastring, 'ipad');
  1114. },
  1115. versionRegexes: [
  1116. /.*?version\/\ ?([0-9]+)\.([0-9]+).*/,
  1117. /.*cpu os ([0-9]+)_([0-9]+).*/,
  1118. /.*cpu iphone os ([0-9]+)_([0-9]+).*/
  1119. ]
  1120. },
  1121. {
  1122. name: 'Android',
  1123. search: checkContains('android'),
  1124. versionRegexes: [/.*?android\ ?([0-9]+)\.([0-9]+).*/]
  1125. },
  1126. {
  1127. name: 'OSX',
  1128. search: checkContains('mac os x'),
  1129. versionRegexes: [/.*?mac\ os\ x\ ?([0-9]+)_([0-9]+).*/]
  1130. },
  1131. {
  1132. name: 'Linux',
  1133. search: checkContains('linux'),
  1134. versionRegexes: []
  1135. },
  1136. {
  1137. name: 'Solaris',
  1138. search: checkContains('sunos'),
  1139. versionRegexes: []
  1140. },
  1141. {
  1142. name: 'FreeBSD',
  1143. search: checkContains('freebsd'),
  1144. versionRegexes: []
  1145. },
  1146. {
  1147. name: 'ChromeOS',
  1148. search: checkContains('cros'),
  1149. versionRegexes: [/.*?chrome\/([0-9]+)\.([0-9]+).*/]
  1150. }
  1151. ];
  1152. var PlatformInfo = {
  1153. browsers: constant(browsers),
  1154. oses: constant(oses)
  1155. };
  1156. var detect$2 = function (userAgent, mediaMatch) {
  1157. var browsers = PlatformInfo.browsers();
  1158. var oses = PlatformInfo.oses();
  1159. var browser = UaString.detectBrowser(browsers, userAgent).fold(Browser.unknown, Browser.nu);
  1160. var os = UaString.detectOs(oses, userAgent).fold(OperatingSystem.unknown, OperatingSystem.nu);
  1161. var deviceType = DeviceType(os, browser, userAgent, mediaMatch);
  1162. return {
  1163. browser: browser,
  1164. os: os,
  1165. deviceType: deviceType
  1166. };
  1167. };
  1168. var PlatformDetection = { detect: detect$2 };
  1169. var mediaMatch = function (query) {
  1170. return domGlobals.window.matchMedia(query).matches;
  1171. };
  1172. var platform = Cell(PlatformDetection.detect(domGlobals.navigator.userAgent, mediaMatch));
  1173. var detect$3 = function () {
  1174. return platform.get();
  1175. };
  1176. var fromHtml = function (html, scope) {
  1177. var doc = scope || domGlobals.document;
  1178. var div = doc.createElement('div');
  1179. div.innerHTML = html;
  1180. if (!div.hasChildNodes() || div.childNodes.length > 1) {
  1181. domGlobals.console.error('HTML does not have a single root node', html);
  1182. throw new Error('HTML must have a single root node');
  1183. }
  1184. return fromDom(div.childNodes[0]);
  1185. };
  1186. var fromTag = function (tag, scope) {
  1187. var doc = scope || domGlobals.document;
  1188. var node = doc.createElement(tag);
  1189. return fromDom(node);
  1190. };
  1191. var fromText = function (text, scope) {
  1192. var doc = scope || domGlobals.document;
  1193. var node = doc.createTextNode(text);
  1194. return fromDom(node);
  1195. };
  1196. var fromDom = function (node) {
  1197. if (node === null || node === undefined) {
  1198. throw new Error('Node cannot be null or undefined');
  1199. }
  1200. return { dom: constant(node) };
  1201. };
  1202. var fromPoint = function (docElm, x, y) {
  1203. var doc = docElm.dom();
  1204. return Option.from(doc.elementFromPoint(x, y)).map(fromDom);
  1205. };
  1206. var Element = {
  1207. fromHtml: fromHtml,
  1208. fromTag: fromTag,
  1209. fromText: fromText,
  1210. fromDom: fromDom,
  1211. fromPoint: fromPoint
  1212. };
  1213. var ATTRIBUTE = domGlobals.Node.ATTRIBUTE_NODE;
  1214. var CDATA_SECTION = domGlobals.Node.CDATA_SECTION_NODE;
  1215. var COMMENT = domGlobals.Node.COMMENT_NODE;
  1216. var DOCUMENT = domGlobals.Node.DOCUMENT_NODE;
  1217. var DOCUMENT_TYPE = domGlobals.Node.DOCUMENT_TYPE_NODE;
  1218. var DOCUMENT_FRAGMENT = domGlobals.Node.DOCUMENT_FRAGMENT_NODE;
  1219. var ELEMENT = domGlobals.Node.ELEMENT_NODE;
  1220. var TEXT = domGlobals.Node.TEXT_NODE;
  1221. var PROCESSING_INSTRUCTION = domGlobals.Node.PROCESSING_INSTRUCTION_NODE;
  1222. var ENTITY_REFERENCE = domGlobals.Node.ENTITY_REFERENCE_NODE;
  1223. var ENTITY = domGlobals.Node.ENTITY_NODE;
  1224. var NOTATION = domGlobals.Node.NOTATION_NODE;
  1225. var ELEMENT$1 = ELEMENT;
  1226. var is = function (element, selector) {
  1227. var dom = element.dom();
  1228. if (dom.nodeType !== ELEMENT$1) {
  1229. return false;
  1230. } else {
  1231. var elem = dom;
  1232. if (elem.matches !== undefined) {
  1233. return elem.matches(selector);
  1234. } else if (elem.msMatchesSelector !== undefined) {
  1235. return elem.msMatchesSelector(selector);
  1236. } else if (elem.webkitMatchesSelector !== undefined) {
  1237. return elem.webkitMatchesSelector(selector);
  1238. } else if (elem.mozMatchesSelector !== undefined) {
  1239. return elem.mozMatchesSelector(selector);
  1240. } else {
  1241. throw new Error('Browser lacks native selectors');
  1242. }
  1243. }
  1244. };
  1245. var regularContains = function (e1, e2) {
  1246. var d1 = e1.dom();
  1247. var d2 = e2.dom();
  1248. return d1 === d2 ? false : d1.contains(d2);
  1249. };
  1250. var ieContains = function (e1, e2) {
  1251. return Node.documentPositionContainedBy(e1.dom(), e2.dom());
  1252. };
  1253. var browser = detect$3().browser;
  1254. var contains$1 = browser.isIE() ? ieContains : regularContains;
  1255. var Global = typeof domGlobals.window !== 'undefined' ? domGlobals.window : Function('return this;')();
  1256. var child = function (scope, predicate) {
  1257. var pred = function (node) {
  1258. return predicate(Element.fromDom(node));
  1259. };
  1260. var result = find(scope.dom().childNodes, pred);
  1261. return result.map(Element.fromDom);
  1262. };
  1263. var child$1 = function (scope, selector) {
  1264. return child(scope, function (e) {
  1265. return is(e, selector);
  1266. });
  1267. };
  1268. var count = 0;
  1269. var getFigureImg = function (elem) {
  1270. return child$1(Element.fromDom(elem), 'img');
  1271. };
  1272. var isFigure = function (editor, elem) {
  1273. return editor.dom.is(elem, 'figure');
  1274. };
  1275. var getEditableImage = function (editor, elem) {
  1276. var isImage = function (imgNode) {
  1277. return editor.dom.is(imgNode, 'img:not([data-mce-object],[data-mce-placeholder])');
  1278. };
  1279. var isEditable = function (imgNode) {
  1280. return isImage(imgNode) && (isLocalImage(editor, imgNode) || isCorsImage(editor, imgNode) || editor.settings.imagetools_proxy);
  1281. };
  1282. if (isFigure(editor, elem)) {
  1283. var imgOpt = getFigureImg(elem);
  1284. return imgOpt.map(function (img) {
  1285. return isEditable(img.dom()) ? Option.some(img.dom()) : Option.none();
  1286. });
  1287. }
  1288. return isEditable(elem) ? Option.some(elem) : Option.none();
  1289. };
  1290. var displayError = function (editor, error) {
  1291. editor.notificationManager.open({
  1292. text: error,
  1293. type: 'error'
  1294. });
  1295. };
  1296. var getSelectedImage = function (editor) {
  1297. var elem = editor.selection.getNode();
  1298. if (isFigure(editor, elem)) {
  1299. return getFigureImg(elem);
  1300. } else {
  1301. return Option.some(Element.fromDom(elem));
  1302. }
  1303. };
  1304. var extractFilename = function (editor, url) {
  1305. var m = url.match(/\/([^\/\?]+)?\.(?:jpeg|jpg|png|gif)(?:\?|$)/i);
  1306. if (m) {
  1307. return editor.dom.encode(m[1]);
  1308. }
  1309. return null;
  1310. };
  1311. var createId = function () {
  1312. return 'imagetools' + count++;
  1313. };
  1314. var isLocalImage = function (editor, img) {
  1315. var url = img.src;
  1316. return url.indexOf('data:') === 0 || url.indexOf('blob:') === 0 || new global$4(url).host === editor.documentBaseURI.host;
  1317. };
  1318. var isCorsImage = function (editor, img) {
  1319. return global$1.inArray(getCorsHosts(editor), new global$4(img.src).host) !== -1;
  1320. };
  1321. var isCorsWithCredentialsImage = function (editor, img) {
  1322. return global$1.inArray(getCredentialsHosts(editor), new global$4(img.src).host) !== -1;
  1323. };
  1324. var defaultFetchImage = function (editor, img) {
  1325. var src = img.src, apiKey;
  1326. if (isCorsImage(editor, img)) {
  1327. return getUrl(img.src, null, isCorsWithCredentialsImage(editor, img));
  1328. }
  1329. if (!isLocalImage(editor, img)) {
  1330. src = getProxyUrl(editor);
  1331. src += (src.indexOf('?') === -1 ? '?' : '&') + 'url=' + encodeURIComponent(img.src);
  1332. apiKey = getApiKey(editor);
  1333. return getUrl(src, apiKey, false);
  1334. }
  1335. return imageToBlob$1(img);
  1336. };
  1337. var imageToBlob$2 = function (editor, img) {
  1338. return getFetchImage(editor).fold(function () {
  1339. return defaultFetchImage(editor, img);
  1340. }, function (customFetchImage) {
  1341. return customFetchImage(img);
  1342. });
  1343. };
  1344. var findBlob = function (editor, img) {
  1345. var blobInfo;
  1346. blobInfo = editor.editorUpload.blobCache.getByUri(img.src);
  1347. if (blobInfo) {
  1348. return global$3.resolve(blobInfo.blob());
  1349. }
  1350. return imageToBlob$2(editor, img);
  1351. };
  1352. var startTimedUpload = function (editor, imageUploadTimerState) {
  1353. var imageUploadTimer = global$2.setEditorTimeout(editor, function () {
  1354. editor.editorUpload.uploadImagesAuto();
  1355. }, getUploadTimeout(editor));
  1356. imageUploadTimerState.set(imageUploadTimer);
  1357. };
  1358. var cancelTimedUpload = function (imageUploadTimerState) {
  1359. global$2.clearTimeout(imageUploadTimerState.get());
  1360. };
  1361. var updateSelectedImage = function (editor, ir, uploadImmediately, imageUploadTimerState, selectedImage, size) {
  1362. return ir.toBlob().then(function (blob) {
  1363. var uri, name, blobCache, blobInfo;
  1364. blobCache = editor.editorUpload.blobCache;
  1365. uri = selectedImage.src;
  1366. if (shouldReuseFilename(editor)) {
  1367. blobInfo = blobCache.getByUri(uri);
  1368. if (blobInfo) {
  1369. uri = blobInfo.uri();
  1370. name = blobInfo.name();
  1371. } else {
  1372. name = extractFilename(editor, uri);
  1373. }
  1374. }
  1375. blobInfo = blobCache.create({
  1376. id: createId(),
  1377. blob: blob,
  1378. base64: ir.toBase64(),
  1379. uri: uri,
  1380. name: name
  1381. });
  1382. blobCache.add(blobInfo);
  1383. editor.undoManager.transact(function () {
  1384. function imageLoadedHandler() {
  1385. editor.$(selectedImage).off('load', imageLoadedHandler);
  1386. editor.nodeChanged();
  1387. if (uploadImmediately) {
  1388. editor.editorUpload.uploadImagesAuto();
  1389. } else {
  1390. cancelTimedUpload(imageUploadTimerState);
  1391. startTimedUpload(editor, imageUploadTimerState);
  1392. }
  1393. }
  1394. editor.$(selectedImage).on('load', imageLoadedHandler);
  1395. if (size) {
  1396. editor.$(selectedImage).attr({
  1397. width: size.w,
  1398. height: size.h
  1399. });
  1400. }
  1401. editor.$(selectedImage).attr({ src: blobInfo.blobUri() }).removeAttr('data-mce-src');
  1402. });
  1403. return blobInfo;
  1404. });
  1405. };
  1406. var selectedImageOperation = function (editor, imageUploadTimerState, fn, size) {
  1407. return function () {
  1408. var imgOpt = getSelectedImage(editor);
  1409. return imgOpt.fold(function () {
  1410. displayError(editor, 'Could not find selected image');
  1411. }, function (img) {
  1412. return editor._scanForImages().then(function () {
  1413. return findBlob(editor, img.dom());
  1414. }).then(blobToImageResult).then(fn).then(function (imageResult) {
  1415. return updateSelectedImage(editor, imageResult, false, imageUploadTimerState, img.dom(), size);
  1416. }, function (error) {
  1417. displayError(editor, error);
  1418. });
  1419. });
  1420. };
  1421. };
  1422. var rotate$2 = function (editor, imageUploadTimerState, angle) {
  1423. return function () {
  1424. var imgOpt = getSelectedImage(editor);
  1425. var flippedSize = imgOpt.fold(function () {
  1426. return null;
  1427. }, function (img) {
  1428. var size = ImageSize.getImageSize(img.dom());
  1429. return size ? {
  1430. w: size.h,
  1431. h: size.w
  1432. } : null;
  1433. });
  1434. return selectedImageOperation(editor, imageUploadTimerState, function (imageResult) {
  1435. return rotate$1(imageResult, angle);
  1436. }, flippedSize)();
  1437. };
  1438. };
  1439. var flip$2 = function (editor, imageUploadTimerState, axis) {
  1440. return function () {
  1441. return selectedImageOperation(editor, imageUploadTimerState, function (imageResult) {
  1442. return flip$1(imageResult, axis);
  1443. })();
  1444. };
  1445. };
  1446. var handleDialogBlob = function (editor, imageUploadTimerState, img, originalSize, blob) {
  1447. return new global$3(function (resolve) {
  1448. blobToImage$1(blob).then(function (newImage) {
  1449. var newSize = ImageSize.getNaturalImageSize(newImage);
  1450. if (originalSize.w !== newSize.w || originalSize.h !== newSize.h) {
  1451. if (ImageSize.getImageSize(img)) {
  1452. ImageSize.setImageSize(img, newSize);
  1453. }
  1454. }
  1455. domGlobals.URL.revokeObjectURL(newImage.src);
  1456. return blob;
  1457. }).then(blobToImageResult).then(function (imageResult) {
  1458. return updateSelectedImage(editor, imageResult, true, imageUploadTimerState, img);
  1459. }, function () {
  1460. });
  1461. });
  1462. };
  1463. var Actions = {
  1464. rotate: rotate$2,
  1465. flip: flip$2,
  1466. getEditableImage: getEditableImage,
  1467. cancelTimedUpload: cancelTimedUpload,
  1468. findBlob: findBlob,
  1469. getSelectedImage: getSelectedImage,
  1470. handleDialogBlob: handleDialogBlob
  1471. };
  1472. var saveState = constant('save-state');
  1473. var disable = constant('disable');
  1474. var enable = constant('enable');
  1475. var createState = function (blob) {
  1476. return {
  1477. blob: blob,
  1478. url: domGlobals.URL.createObjectURL(blob)
  1479. };
  1480. };
  1481. var makeOpen = function (editor, imageUploadTimerState) {
  1482. return function () {
  1483. var getLoadedSpec = function (currentState) {
  1484. return {
  1485. title: 'Edit Image',
  1486. size: 'large',
  1487. body: {
  1488. type: 'panel',
  1489. items: [{
  1490. type: 'imagetools',
  1491. name: 'imagetools',
  1492. label: 'Edit Image',
  1493. currentState: currentState
  1494. }]
  1495. },
  1496. buttons: [
  1497. {
  1498. type: 'cancel',
  1499. name: 'cancel',
  1500. text: 'Cancel'
  1501. },
  1502. {
  1503. type: 'submit',
  1504. name: 'save',
  1505. text: 'Save',
  1506. primary: true,
  1507. disabled: true
  1508. }
  1509. ],
  1510. onSubmit: function (api) {
  1511. var blob = api.getData().imagetools.blob;
  1512. originalImgOpt.each(function (originalImg) {
  1513. originalSizeOpt.each(function (originalSize) {
  1514. Actions.handleDialogBlob(editor, imageUploadTimerState, originalImg.dom(), originalSize, blob);
  1515. });
  1516. });
  1517. api.close();
  1518. },
  1519. onCancel: function () {
  1520. },
  1521. onAction: function (api, details) {
  1522. switch (details.name) {
  1523. case saveState():
  1524. if (details.value) {
  1525. api.enable('save');
  1526. } else {
  1527. api.disable('save');
  1528. }
  1529. break;
  1530. case disable():
  1531. api.disable('save');
  1532. api.disable('cancel');
  1533. break;
  1534. case enable():
  1535. api.enable('cancel');
  1536. break;
  1537. }
  1538. }
  1539. };
  1540. };
  1541. var originalImgOpt = Actions.getSelectedImage(editor);
  1542. var originalSizeOpt = originalImgOpt.map(function (origImg) {
  1543. return ImageSize.getNaturalImageSize(origImg.dom());
  1544. });
  1545. var imgOpt = Actions.getSelectedImage(editor);
  1546. imgOpt.each(function (img) {
  1547. Actions.getEditableImage(editor, img.dom()).each(function (_) {
  1548. Actions.findBlob(editor, img.dom()).then(function (blob) {
  1549. var state = createState(blob);
  1550. editor.windowManager.open(getLoadedSpec(state));
  1551. });
  1552. });
  1553. });
  1554. };
  1555. };
  1556. var Dialog = { makeOpen: makeOpen };
  1557. var register = function (editor, imageUploadTimerState) {
  1558. global$1.each({
  1559. mceImageRotateLeft: Actions.rotate(editor, imageUploadTimerState, -90),
  1560. mceImageRotateRight: Actions.rotate(editor, imageUploadTimerState, 90),
  1561. mceImageFlipVertical: Actions.flip(editor, imageUploadTimerState, 'v'),
  1562. mceImageFlipHorizontal: Actions.flip(editor, imageUploadTimerState, 'h'),
  1563. mceEditImage: Dialog.makeOpen(editor, imageUploadTimerState)
  1564. }, function (fn, cmd) {
  1565. editor.addCommand(cmd, fn);
  1566. });
  1567. };
  1568. var Commands = { register: register };
  1569. var setup = function (editor, imageUploadTimerState, lastSelectedImageState) {
  1570. editor.on('NodeChange', function (e) {
  1571. var lastSelectedImage = lastSelectedImageState.get();
  1572. if (lastSelectedImage && lastSelectedImage.src !== e.element.src) {
  1573. Actions.cancelTimedUpload(imageUploadTimerState);
  1574. editor.editorUpload.uploadImagesAuto();
  1575. lastSelectedImageState.set(null);
  1576. }
  1577. Actions.getEditableImage(editor, e.element).each(lastSelectedImageState.set);
  1578. });
  1579. };
  1580. var UploadSelectedImage = { setup: setup };
  1581. var register$1 = function (editor) {
  1582. var cmd = function (command) {
  1583. return function () {
  1584. return editor.execCommand(command);
  1585. };
  1586. };
  1587. editor.ui.registry.addButton('rotateleft', {
  1588. tooltip: 'Rotate counterclockwise',
  1589. icon: 'rotate-left',
  1590. onAction: cmd('mceImageRotateLeft')
  1591. });
  1592. editor.ui.registry.addButton('rotateright', {
  1593. tooltip: 'Rotate clockwise',
  1594. icon: 'rotate-right',
  1595. onAction: cmd('mceImageRotateRight')
  1596. });
  1597. editor.ui.registry.addButton('flipv', {
  1598. tooltip: 'Flip vertically',
  1599. icon: 'flip-vertically',
  1600. onAction: cmd('mceImageFlipVertical')
  1601. });
  1602. editor.ui.registry.addButton('fliph', {
  1603. tooltip: 'Flip horizontally',
  1604. icon: 'flip-horizontally',
  1605. onAction: cmd('mceImageFlipHorizontal')
  1606. });
  1607. editor.ui.registry.addButton('editimage', {
  1608. tooltip: 'Edit image',
  1609. icon: 'edit-image',
  1610. onAction: cmd('mceEditImage'),
  1611. onSetup: function (buttonApi) {
  1612. var setDisabled = function () {
  1613. var elementOpt = Actions.getSelectedImage(editor);
  1614. elementOpt.each(function (element) {
  1615. var disabled = Actions.getEditableImage(editor, element.dom()).isNone();
  1616. buttonApi.setDisabled(disabled);
  1617. });
  1618. };
  1619. editor.on('NodeChange', setDisabled);
  1620. return function () {
  1621. editor.off('NodeChange', setDisabled);
  1622. };
  1623. }
  1624. });
  1625. editor.ui.registry.addButton('imageoptions', {
  1626. tooltip: 'Image options',
  1627. icon: 'image-options',
  1628. onAction: cmd('mceImage')
  1629. });
  1630. editor.ui.registry.addContextMenu('imagetools', {
  1631. update: function (element) {
  1632. return Actions.getEditableImage(editor, element).fold(function () {
  1633. return [];
  1634. }, function (_) {
  1635. return [{
  1636. text: 'Edit image',
  1637. icon: 'edit-image',
  1638. onAction: cmd('mceEditImage')
  1639. }];
  1640. });
  1641. }
  1642. });
  1643. };
  1644. var Buttons = { register: register$1 };
  1645. var register$2 = function (editor) {
  1646. editor.ui.registry.addContextToolbar('imagetools', {
  1647. items: getToolbarItems(editor),
  1648. predicate: function (elem) {
  1649. return Actions.getEditableImage(editor, elem).isSome();
  1650. },
  1651. position: 'node',
  1652. scope: 'node'
  1653. });
  1654. };
  1655. var ContextToolbar = { register: register$2 };
  1656. function Plugin () {
  1657. global.add('imagetools', function (editor) {
  1658. var imageUploadTimerState = Cell(0);
  1659. var lastSelectedImageState = Cell(null);
  1660. Commands.register(editor, imageUploadTimerState);
  1661. Buttons.register(editor);
  1662. ContextToolbar.register(editor);
  1663. UploadSelectedImage.setup(editor, imageUploadTimerState, lastSelectedImageState);
  1664. });
  1665. }
  1666. Plugin();
  1667. }(window));