plugin.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474
  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.10.2 (2021-11-17)
  8. */
  9. (function () {
  10. 'use strict';
  11. var global$3 = tinymce.util.Tools.resolve('tinymce.PluginManager');
  12. var unique = 0;
  13. var generate = function (prefix) {
  14. var date = new Date();
  15. var time = date.getTime();
  16. var random = Math.floor(Math.random() * 1000000000);
  17. unique++;
  18. return prefix + '_' + random + unique + String(time);
  19. };
  20. var createTableHtml = function (cols, rows) {
  21. var html = '<table data-mce-id="mce" style="width: 100%">';
  22. html += '<tbody>';
  23. for (var y = 0; y < rows; y++) {
  24. html += '<tr>';
  25. for (var x = 0; x < cols; x++) {
  26. html += '<td><br></td>';
  27. }
  28. html += '</tr>';
  29. }
  30. html += '</tbody>';
  31. html += '</table>';
  32. return html;
  33. };
  34. var getInsertedElement = function (editor) {
  35. var elms = editor.dom.select('*[data-mce-id]');
  36. return elms[0];
  37. };
  38. var insertTableHtml = function (editor, cols, rows) {
  39. editor.undoManager.transact(function () {
  40. editor.insertContent(createTableHtml(cols, rows));
  41. var tableElm = getInsertedElement(editor);
  42. tableElm.removeAttribute('data-mce-id');
  43. var cellElm = editor.dom.select('td,th', tableElm);
  44. editor.selection.setCursorLocation(cellElm[0], 0);
  45. });
  46. };
  47. var insertTable = function (editor, cols, rows) {
  48. editor.plugins.table ? editor.plugins.table.insertTable(cols, rows) : insertTableHtml(editor, cols, rows);
  49. };
  50. var insertBlob = function (editor, base64, blob) {
  51. var blobCache = editor.editorUpload.blobCache;
  52. var blobInfo = blobCache.create(generate('mceu'), blob, base64);
  53. blobCache.add(blobInfo);
  54. editor.insertContent(editor.dom.createHTML('img', { src: blobInfo.blobUri() }));
  55. };
  56. var global$2 = tinymce.util.Tools.resolve('tinymce.util.Promise');
  57. var blobToBase64 = function (blob) {
  58. return new global$2(function (resolve) {
  59. var reader = new FileReader();
  60. reader.onloadend = function () {
  61. resolve(reader.result.split(',')[1]);
  62. };
  63. reader.readAsDataURL(blob);
  64. });
  65. };
  66. var global$1 = tinymce.util.Tools.resolve('tinymce.Env');
  67. var global = tinymce.util.Tools.resolve('tinymce.util.Delay');
  68. var pickFile = function (editor) {
  69. return new global$2(function (resolve) {
  70. var fileInput = document.createElement('input');
  71. fileInput.type = 'file';
  72. fileInput.accept = 'image/*';
  73. fileInput.style.position = 'fixed';
  74. fileInput.style.left = '0';
  75. fileInput.style.top = '0';
  76. fileInput.style.opacity = '0.001';
  77. document.body.appendChild(fileInput);
  78. var changeHandler = function (e) {
  79. resolve(Array.prototype.slice.call(e.target.files));
  80. };
  81. fileInput.addEventListener('change', changeHandler);
  82. var cancelHandler = function (e) {
  83. var cleanup = function () {
  84. resolve([]);
  85. fileInput.parentNode.removeChild(fileInput);
  86. };
  87. if (global$1.os.isAndroid() && e.type !== 'remove') {
  88. global.setEditorTimeout(editor, cleanup, 0);
  89. } else {
  90. cleanup();
  91. }
  92. editor.off('focusin remove', cancelHandler);
  93. };
  94. editor.on('focusin remove', cancelHandler);
  95. fileInput.click();
  96. });
  97. };
  98. var setupButtons = function (editor) {
  99. editor.ui.registry.addButton('quickimage', {
  100. icon: 'image',
  101. tooltip: 'Insert image',
  102. onAction: function () {
  103. pickFile(editor).then(function (files) {
  104. if (files.length > 0) {
  105. var blob_1 = files[0];
  106. blobToBase64(blob_1).then(function (base64) {
  107. insertBlob(editor, base64, blob_1);
  108. });
  109. }
  110. });
  111. }
  112. });
  113. editor.ui.registry.addButton('quicktable', {
  114. icon: 'table',
  115. tooltip: 'Insert table',
  116. onAction: function () {
  117. insertTable(editor, 2, 2);
  118. }
  119. });
  120. };
  121. var typeOf = function (x) {
  122. var t = typeof x;
  123. if (x === null) {
  124. return 'null';
  125. } else if (t === 'object' && (Array.prototype.isPrototypeOf(x) || x.constructor && x.constructor.name === 'Array')) {
  126. return 'array';
  127. } else if (t === 'object' && (String.prototype.isPrototypeOf(x) || x.constructor && x.constructor.name === 'String')) {
  128. return 'string';
  129. } else {
  130. return t;
  131. }
  132. };
  133. var isType = function (type) {
  134. return function (value) {
  135. return typeOf(value) === type;
  136. };
  137. };
  138. var isSimpleType = function (type) {
  139. return function (value) {
  140. return typeof value === type;
  141. };
  142. };
  143. var eq = function (t) {
  144. return function (a) {
  145. return t === a;
  146. };
  147. };
  148. var isString = isType('string');
  149. var isObject = isType('object');
  150. var isArray = isType('array');
  151. var isBoolean = isSimpleType('boolean');
  152. var isUndefined = eq(undefined);
  153. var isFunction = isSimpleType('function');
  154. var noop = function () {
  155. };
  156. var constant = function (value) {
  157. return function () {
  158. return value;
  159. };
  160. };
  161. var identity = function (x) {
  162. return x;
  163. };
  164. var never = constant(false);
  165. var always = constant(true);
  166. var none = function () {
  167. return NONE;
  168. };
  169. var NONE = function () {
  170. var call = function (thunk) {
  171. return thunk();
  172. };
  173. var id = identity;
  174. var me = {
  175. fold: function (n, _s) {
  176. return n();
  177. },
  178. isSome: never,
  179. isNone: always,
  180. getOr: id,
  181. getOrThunk: call,
  182. getOrDie: function (msg) {
  183. throw new Error(msg || 'error: getOrDie called on none.');
  184. },
  185. getOrNull: constant(null),
  186. getOrUndefined: constant(undefined),
  187. or: id,
  188. orThunk: call,
  189. map: none,
  190. each: noop,
  191. bind: none,
  192. exists: never,
  193. forall: always,
  194. filter: function () {
  195. return none();
  196. },
  197. toArray: function () {
  198. return [];
  199. },
  200. toString: constant('none()')
  201. };
  202. return me;
  203. }();
  204. var some = function (a) {
  205. var constant_a = constant(a);
  206. var self = function () {
  207. return me;
  208. };
  209. var bind = function (f) {
  210. return f(a);
  211. };
  212. var me = {
  213. fold: function (n, s) {
  214. return s(a);
  215. },
  216. isSome: always,
  217. isNone: never,
  218. getOr: constant_a,
  219. getOrThunk: constant_a,
  220. getOrDie: constant_a,
  221. getOrNull: constant_a,
  222. getOrUndefined: constant_a,
  223. or: self,
  224. orThunk: self,
  225. map: function (f) {
  226. return some(f(a));
  227. },
  228. each: function (f) {
  229. f(a);
  230. },
  231. bind: bind,
  232. exists: bind,
  233. forall: bind,
  234. filter: function (f) {
  235. return f(a) ? me : NONE;
  236. },
  237. toArray: function () {
  238. return [a];
  239. },
  240. toString: function () {
  241. return 'some(' + a + ')';
  242. }
  243. };
  244. return me;
  245. };
  246. var from = function (value) {
  247. return value === null || value === undefined ? NONE : some(value);
  248. };
  249. var Optional = {
  250. some: some,
  251. none: none,
  252. from: from
  253. };
  254. function ClosestOrAncestor (is, ancestor, scope, a, isRoot) {
  255. if (is(scope, a)) {
  256. return Optional.some(scope);
  257. } else if (isFunction(isRoot) && isRoot(scope)) {
  258. return Optional.none();
  259. } else {
  260. return ancestor(scope, a, isRoot);
  261. }
  262. }
  263. var ELEMENT = 1;
  264. var fromHtml = function (html, scope) {
  265. var doc = scope || document;
  266. var div = doc.createElement('div');
  267. div.innerHTML = html;
  268. if (!div.hasChildNodes() || div.childNodes.length > 1) {
  269. console.error('HTML does not have a single root node', html);
  270. throw new Error('HTML must have a single root node');
  271. }
  272. return fromDom(div.childNodes[0]);
  273. };
  274. var fromTag = function (tag, scope) {
  275. var doc = scope || document;
  276. var node = doc.createElement(tag);
  277. return fromDom(node);
  278. };
  279. var fromText = function (text, scope) {
  280. var doc = scope || document;
  281. var node = doc.createTextNode(text);
  282. return fromDom(node);
  283. };
  284. var fromDom = function (node) {
  285. if (node === null || node === undefined) {
  286. throw new Error('Node cannot be null or undefined');
  287. }
  288. return { dom: node };
  289. };
  290. var fromPoint = function (docElm, x, y) {
  291. return Optional.from(docElm.dom.elementFromPoint(x, y)).map(fromDom);
  292. };
  293. var SugarElement = {
  294. fromHtml: fromHtml,
  295. fromTag: fromTag,
  296. fromText: fromText,
  297. fromDom: fromDom,
  298. fromPoint: fromPoint
  299. };
  300. var is = function (element, selector) {
  301. var dom = element.dom;
  302. if (dom.nodeType !== ELEMENT) {
  303. return false;
  304. } else {
  305. var elem = dom;
  306. if (elem.matches !== undefined) {
  307. return elem.matches(selector);
  308. } else if (elem.msMatchesSelector !== undefined) {
  309. return elem.msMatchesSelector(selector);
  310. } else if (elem.webkitMatchesSelector !== undefined) {
  311. return elem.webkitMatchesSelector(selector);
  312. } else if (elem.mozMatchesSelector !== undefined) {
  313. return elem.mozMatchesSelector(selector);
  314. } else {
  315. throw new Error('Browser lacks native selectors');
  316. }
  317. }
  318. };
  319. typeof window !== 'undefined' ? window : Function('return this;')();
  320. var name = function (element) {
  321. var r = element.dom.nodeName;
  322. return r.toLowerCase();
  323. };
  324. var ancestor$1 = function (scope, predicate, isRoot) {
  325. var element = scope.dom;
  326. var stop = isFunction(isRoot) ? isRoot : never;
  327. while (element.parentNode) {
  328. element = element.parentNode;
  329. var el = SugarElement.fromDom(element);
  330. if (predicate(el)) {
  331. return Optional.some(el);
  332. } else if (stop(el)) {
  333. break;
  334. }
  335. }
  336. return Optional.none();
  337. };
  338. var closest$1 = function (scope, predicate, isRoot) {
  339. var is = function (s, test) {
  340. return test(s);
  341. };
  342. return ClosestOrAncestor(is, ancestor$1, scope, predicate, isRoot);
  343. };
  344. var ancestor = function (scope, selector, isRoot) {
  345. return ancestor$1(scope, function (e) {
  346. return is(e, selector);
  347. }, isRoot);
  348. };
  349. var closest = function (scope, selector, isRoot) {
  350. var is$1 = function (element, selector) {
  351. return is(element, selector);
  352. };
  353. return ClosestOrAncestor(is$1, ancestor, scope, selector, isRoot);
  354. };
  355. var validDefaultOrDie = function (value, predicate) {
  356. if (predicate(value)) {
  357. return true;
  358. }
  359. throw new Error('Default value doesn\'t match requested type.');
  360. };
  361. var items = function (value, defaultValue) {
  362. if (isArray(value) || isObject(value)) {
  363. throw new Error('expected a string but found: ' + value);
  364. }
  365. if (isUndefined(value)) {
  366. return defaultValue;
  367. }
  368. if (isBoolean(value)) {
  369. return value === false ? '' : defaultValue;
  370. }
  371. return value;
  372. };
  373. var getToolbarItemsOr_ = function (predicate) {
  374. return function (editor, name, defaultValue) {
  375. validDefaultOrDie(defaultValue, predicate);
  376. var value = editor.getParam(name, defaultValue);
  377. return items(value, defaultValue);
  378. };
  379. };
  380. var getToolbarItemsOr = getToolbarItemsOr_(isString);
  381. var getTextSelectionToolbarItems = function (editor) {
  382. return getToolbarItemsOr(editor, 'quickbars_selection_toolbar', 'bold italic | quicklink h2 h3 blockquote');
  383. };
  384. var getInsertToolbarItems = function (editor) {
  385. return getToolbarItemsOr(editor, 'quickbars_insert_toolbar', 'quickimage quicktable');
  386. };
  387. var getImageToolbarItems = function (editor) {
  388. return getToolbarItemsOr(editor, 'quickbars_image_toolbar', 'alignleft aligncenter alignright');
  389. };
  390. var addToEditor$1 = function (editor) {
  391. var insertToolbarItems = getInsertToolbarItems(editor);
  392. if (insertToolbarItems.trim().length > 0) {
  393. editor.ui.registry.addContextToolbar('quickblock', {
  394. predicate: function (node) {
  395. var sugarNode = SugarElement.fromDom(node);
  396. var textBlockElementsMap = editor.schema.getTextBlockElements();
  397. var isRoot = function (elem) {
  398. return elem.dom === editor.getBody();
  399. };
  400. return closest(sugarNode, 'table', isRoot).fold(function () {
  401. return closest$1(sugarNode, function (elem) {
  402. return name(elem) in textBlockElementsMap && editor.dom.isEmpty(elem.dom);
  403. }, isRoot).isSome();
  404. }, never);
  405. },
  406. items: insertToolbarItems,
  407. position: 'line',
  408. scope: 'editor'
  409. });
  410. }
  411. };
  412. var addToEditor = function (editor) {
  413. var isEditable = function (node) {
  414. return editor.dom.getContentEditableParent(node) !== 'false';
  415. };
  416. var isImage = function (node) {
  417. return node.nodeName === 'IMG' || node.nodeName === 'FIGURE' && /image/i.test(node.className);
  418. };
  419. var imageToolbarItems = getImageToolbarItems(editor);
  420. if (imageToolbarItems.trim().length > 0) {
  421. editor.ui.registry.addContextToolbar('imageselection', {
  422. predicate: isImage,
  423. items: imageToolbarItems,
  424. position: 'node'
  425. });
  426. }
  427. var textToolbarItems = getTextSelectionToolbarItems(editor);
  428. if (textToolbarItems.trim().length > 0) {
  429. editor.ui.registry.addContextToolbar('textselection', {
  430. predicate: function (node) {
  431. return !isImage(node) && !editor.selection.isCollapsed() && isEditable(node);
  432. },
  433. items: textToolbarItems,
  434. position: 'selection',
  435. scope: 'editor'
  436. });
  437. }
  438. };
  439. function Plugin () {
  440. global$3.add('quickbars', function (editor) {
  441. setupButtons(editor);
  442. addToEditor$1(editor);
  443. addToEditor(editor);
  444. });
  445. }
  446. Plugin();
  447. }());