plugin.js 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555
  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.3.0 (2020-05-21)
  8. */
  9. (function () {
  10. 'use strict';
  11. var global = tinymce.util.Tools.resolve('tinymce.PluginManager');
  12. var noop = function () {
  13. };
  14. var constant = function (value) {
  15. return function () {
  16. return value;
  17. };
  18. };
  19. function curry(fn) {
  20. var initialArgs = [];
  21. for (var _i = 1; _i < arguments.length; _i++) {
  22. initialArgs[_i - 1] = arguments[_i];
  23. }
  24. return function () {
  25. var restArgs = [];
  26. for (var _i = 0; _i < arguments.length; _i++) {
  27. restArgs[_i] = arguments[_i];
  28. }
  29. var all = initialArgs.concat(restArgs);
  30. return fn.apply(null, all);
  31. };
  32. }
  33. var never = constant(false);
  34. var always = constant(true);
  35. var global$1 = tinymce.util.Tools.resolve('tinymce.util.Tools');
  36. var global$2 = tinymce.util.Tools.resolve('tinymce.util.XHR');
  37. var getCreationDateClasses = function (editor) {
  38. return editor.getParam('template_cdate_classes', 'cdate');
  39. };
  40. var getModificationDateClasses = function (editor) {
  41. return editor.getParam('template_mdate_classes', 'mdate');
  42. };
  43. var getSelectedContentClasses = function (editor) {
  44. return editor.getParam('template_selected_content_classes', 'selcontent');
  45. };
  46. var getPreviewReplaceValues = function (editor) {
  47. return editor.getParam('template_preview_replace_values');
  48. };
  49. var getTemplateReplaceValues = function (editor) {
  50. return editor.getParam('template_replace_values');
  51. };
  52. var getTemplates = function (editorSettings) {
  53. return editorSettings.templates;
  54. };
  55. var getCdateFormat = function (editor) {
  56. return editor.getParam('template_cdate_format', editor.translate('%Y-%m-%d'));
  57. };
  58. var getMdateFormat = function (editor) {
  59. return editor.getParam('template_mdate_format', editor.translate('%Y-%m-%d'));
  60. };
  61. var addZeros = function (value, len) {
  62. value = '' + value;
  63. if (value.length < len) {
  64. for (var i = 0; i < len - value.length; i++) {
  65. value = '0' + value;
  66. }
  67. }
  68. return value;
  69. };
  70. var getDateTime = function (editor, fmt, date) {
  71. var daysShort = 'Sun Mon Tue Wed Thu Fri Sat Sun'.split(' ');
  72. var daysLong = 'Sunday Monday Tuesday Wednesday Thursday Friday Saturday Sunday'.split(' ');
  73. var monthsShort = 'Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec'.split(' ');
  74. var monthsLong = 'January February March April May June July August September October November December'.split(' ');
  75. date = date || new Date();
  76. fmt = fmt.replace('%D', '%m/%d/%Y');
  77. fmt = fmt.replace('%r', '%I:%M:%S %p');
  78. fmt = fmt.replace('%Y', '' + date.getFullYear());
  79. fmt = fmt.replace('%y', '' + date.getYear());
  80. fmt = fmt.replace('%m', addZeros(date.getMonth() + 1, 2));
  81. fmt = fmt.replace('%d', addZeros(date.getDate(), 2));
  82. fmt = fmt.replace('%H', '' + addZeros(date.getHours(), 2));
  83. fmt = fmt.replace('%M', '' + addZeros(date.getMinutes(), 2));
  84. fmt = fmt.replace('%S', '' + addZeros(date.getSeconds(), 2));
  85. fmt = fmt.replace('%I', '' + ((date.getHours() + 11) % 12 + 1));
  86. fmt = fmt.replace('%p', '' + (date.getHours() < 12 ? 'AM' : 'PM'));
  87. fmt = fmt.replace('%B', '' + editor.translate(monthsLong[date.getMonth()]));
  88. fmt = fmt.replace('%b', '' + editor.translate(monthsShort[date.getMonth()]));
  89. fmt = fmt.replace('%A', '' + editor.translate(daysLong[date.getDay()]));
  90. fmt = fmt.replace('%a', '' + editor.translate(daysShort[date.getDay()]));
  91. fmt = fmt.replace('%%', '%');
  92. return fmt;
  93. };
  94. var createTemplateList = function (editorSettings, callback) {
  95. return function () {
  96. var templateList = getTemplates(editorSettings);
  97. if (typeof templateList === 'function') {
  98. templateList(callback);
  99. return;
  100. }
  101. if (typeof templateList === 'string') {
  102. global$2.send({
  103. url: templateList,
  104. success: function (text) {
  105. callback(JSON.parse(text));
  106. }
  107. });
  108. } else {
  109. callback(templateList);
  110. }
  111. };
  112. };
  113. var replaceTemplateValues = function (html, templateValues) {
  114. global$1.each(templateValues, function (v, k) {
  115. if (typeof v === 'function') {
  116. v = v(k);
  117. }
  118. html = html.replace(new RegExp('\\{\\$' + k + '\\}', 'g'), v);
  119. });
  120. return html;
  121. };
  122. var replaceVals = function (editor, e) {
  123. var dom = editor.dom, vl = getTemplateReplaceValues(editor);
  124. global$1.each(dom.select('*', e), function (e) {
  125. global$1.each(vl, function (v, k) {
  126. if (dom.hasClass(e, k)) {
  127. if (typeof vl[k] === 'function') {
  128. vl[k](e);
  129. }
  130. }
  131. });
  132. });
  133. };
  134. var hasClass = function (n, c) {
  135. return new RegExp('\\b' + c + '\\b', 'g').test(n.className);
  136. };
  137. var insertTemplate = function (editor, ui, html) {
  138. var el;
  139. var n;
  140. var dom = editor.dom;
  141. var sel = editor.selection.getContent();
  142. html = replaceTemplateValues(html, getTemplateReplaceValues(editor));
  143. el = dom.create('div', null, html);
  144. n = dom.select('.mceTmpl', el);
  145. if (n && n.length > 0) {
  146. el = dom.create('div', null);
  147. el.appendChild(n[0].cloneNode(true));
  148. }
  149. global$1.each(dom.select('*', el), function (n) {
  150. if (hasClass(n, getCreationDateClasses(editor).replace(/\s+/g, '|'))) {
  151. n.innerHTML = getDateTime(editor, getCdateFormat(editor));
  152. }
  153. if (hasClass(n, getModificationDateClasses(editor).replace(/\s+/g, '|'))) {
  154. n.innerHTML = getDateTime(editor, getMdateFormat(editor));
  155. }
  156. if (hasClass(n, getSelectedContentClasses(editor).replace(/\s+/g, '|'))) {
  157. n.innerHTML = sel;
  158. }
  159. });
  160. replaceVals(editor, el);
  161. editor.execCommand('mceInsertContent', false, el.innerHTML);
  162. editor.addVisual();
  163. };
  164. var register = function (editor) {
  165. editor.addCommand('mceInsertTemplate', curry(insertTemplate, editor));
  166. };
  167. var setup = function (editor) {
  168. editor.on('PreProcess', function (o) {
  169. var dom = editor.dom, dateFormat = getMdateFormat(editor);
  170. global$1.each(dom.select('div', o.node), function (e) {
  171. if (dom.hasClass(e, 'mceTmpl')) {
  172. global$1.each(dom.select('*', e), function (e) {
  173. if (dom.hasClass(e, editor.getParam('template_mdate_classes', 'mdate').replace(/\s+/g, '|'))) {
  174. e.innerHTML = getDateTime(editor, dateFormat);
  175. }
  176. });
  177. replaceVals(editor, e);
  178. }
  179. });
  180. });
  181. };
  182. var none = function () {
  183. return NONE;
  184. };
  185. var NONE = function () {
  186. var eq = function (o) {
  187. return o.isNone();
  188. };
  189. var call = function (thunk) {
  190. return thunk();
  191. };
  192. var id = function (n) {
  193. return n;
  194. };
  195. var me = {
  196. fold: function (n, _s) {
  197. return n();
  198. },
  199. is: never,
  200. isSome: never,
  201. isNone: always,
  202. getOr: id,
  203. getOrThunk: call,
  204. getOrDie: function (msg) {
  205. throw new Error(msg || 'error: getOrDie called on none.');
  206. },
  207. getOrNull: constant(null),
  208. getOrUndefined: constant(undefined),
  209. or: id,
  210. orThunk: call,
  211. map: none,
  212. each: noop,
  213. bind: none,
  214. exists: never,
  215. forall: always,
  216. filter: none,
  217. equals: eq,
  218. equals_: eq,
  219. toArray: function () {
  220. return [];
  221. },
  222. toString: constant('none()')
  223. };
  224. return me;
  225. }();
  226. var some = function (a) {
  227. var constant_a = constant(a);
  228. var self = function () {
  229. return me;
  230. };
  231. var bind = function (f) {
  232. return f(a);
  233. };
  234. var me = {
  235. fold: function (n, s) {
  236. return s(a);
  237. },
  238. is: function (v) {
  239. return a === v;
  240. },
  241. isSome: always,
  242. isNone: never,
  243. getOr: constant_a,
  244. getOrThunk: constant_a,
  245. getOrDie: constant_a,
  246. getOrNull: constant_a,
  247. getOrUndefined: constant_a,
  248. or: self,
  249. orThunk: self,
  250. map: function (f) {
  251. return some(f(a));
  252. },
  253. each: function (f) {
  254. f(a);
  255. },
  256. bind: bind,
  257. exists: bind,
  258. forall: bind,
  259. filter: function (f) {
  260. return f(a) ? me : NONE;
  261. },
  262. toArray: function () {
  263. return [a];
  264. },
  265. toString: function () {
  266. return 'some(' + a + ')';
  267. },
  268. equals: function (o) {
  269. return o.is(a);
  270. },
  271. equals_: function (o, elementEq) {
  272. return o.fold(never, function (b) {
  273. return elementEq(a, b);
  274. });
  275. }
  276. };
  277. return me;
  278. };
  279. var from = function (value) {
  280. return value === null || value === undefined ? NONE : some(value);
  281. };
  282. var Option = {
  283. some: some,
  284. none: none,
  285. from: from
  286. };
  287. var map = function (xs, f) {
  288. var len = xs.length;
  289. var r = new Array(len);
  290. for (var i = 0; i < len; i++) {
  291. var x = xs[i];
  292. r[i] = f(x, i);
  293. }
  294. return r;
  295. };
  296. var findUntil = function (xs, pred, until) {
  297. for (var i = 0, len = xs.length; i < len; i++) {
  298. var x = xs[i];
  299. if (pred(x, i)) {
  300. return Option.some(x);
  301. } else if (until(x, i)) {
  302. break;
  303. }
  304. }
  305. return Option.none();
  306. };
  307. var find = function (xs, pred) {
  308. return findUntil(xs, pred, never);
  309. };
  310. var global$3 = tinymce.util.Tools.resolve('tinymce.util.Promise');
  311. var hasOwnProperty = Object.hasOwnProperty;
  312. var get = function (obj, key) {
  313. return has(obj, key) ? Option.from(obj[key]) : Option.none();
  314. };
  315. var has = function (obj, key) {
  316. return hasOwnProperty.call(obj, key);
  317. };
  318. var entitiesAttr = {
  319. '"': '&quot;',
  320. '<': '&lt;',
  321. '>': '&gt;',
  322. '&': '&amp;',
  323. '\'': '&#039;'
  324. };
  325. var htmlEscape = function (html) {
  326. return html.replace(/["'<>&]/g, function (match) {
  327. return get(entitiesAttr, match).getOr(match);
  328. });
  329. };
  330. var getPreviewContent = function (editor, html) {
  331. if (html.indexOf('<html>') === -1) {
  332. var contentCssLinks_1 = '';
  333. global$1.each(editor.contentCSS, function (url) {
  334. contentCssLinks_1 += '<link type="text/css" rel="stylesheet" href="' + editor.documentBaseURI.toAbsolute(url) + '">';
  335. });
  336. var bodyClass = editor.settings.body_class || '';
  337. if (bodyClass.indexOf('=') !== -1) {
  338. bodyClass = editor.getParam('body_class', '', 'hash');
  339. bodyClass = bodyClass[editor.id] || '';
  340. }
  341. var encode = editor.dom.encode;
  342. var directionality = editor.getBody().dir;
  343. var dirAttr = directionality ? ' dir="' + encode(directionality) + '"' : '';
  344. html = '<!DOCTYPE html>' + '<html>' + '<head>' + contentCssLinks_1 + '</head>' + '<body class="' + encode(bodyClass) + '"' + dirAttr + '>' + html + '</body>' + '</html>';
  345. }
  346. return replaceTemplateValues(html, getPreviewReplaceValues(editor));
  347. };
  348. var open = function (editor, templateList) {
  349. var createTemplates = function () {
  350. if (!templateList || templateList.length === 0) {
  351. var message = editor.translate('No templates defined.');
  352. editor.notificationManager.open({
  353. text: message,
  354. type: 'info'
  355. });
  356. return Option.none();
  357. }
  358. return Option.from(global$1.map(templateList, function (template, index) {
  359. var isUrlTemplate = function (t) {
  360. return t.url !== undefined;
  361. };
  362. return {
  363. selected: index === 0,
  364. text: template.title,
  365. value: {
  366. url: isUrlTemplate(template) ? Option.from(template.url) : Option.none(),
  367. content: !isUrlTemplate(template) ? Option.from(template.content) : Option.none(),
  368. description: template.description
  369. }
  370. };
  371. }));
  372. };
  373. var createSelectBoxItems = function (templates) {
  374. return map(templates, function (t) {
  375. return {
  376. text: t.text,
  377. value: t.text
  378. };
  379. });
  380. };
  381. var findTemplate = function (templates, templateTitle) {
  382. return find(templates, function (t) {
  383. return t.text === templateTitle;
  384. });
  385. };
  386. var loadFailedAlert = function (api) {
  387. editor.windowManager.alert('Could not load the specified template.', function () {
  388. return api.focus('template');
  389. });
  390. };
  391. var getTemplateContent = function (t) {
  392. return new global$3(function (resolve, reject) {
  393. t.value.url.fold(function () {
  394. return resolve(t.value.content.getOr(''));
  395. }, function (url) {
  396. return global$2.send({
  397. url: url,
  398. success: function (html) {
  399. resolve(html);
  400. },
  401. error: function (e) {
  402. reject(e);
  403. }
  404. });
  405. });
  406. });
  407. };
  408. var onChange = function (templates, updateDialog) {
  409. return function (api, change) {
  410. if (change.name === 'template') {
  411. var newTemplateTitle = api.getData().template;
  412. findTemplate(templates, newTemplateTitle).each(function (t) {
  413. api.block('Loading...');
  414. getTemplateContent(t).then(function (previewHtml) {
  415. updateDialog(api, t, previewHtml);
  416. }).catch(function () {
  417. updateDialog(api, t, '');
  418. api.disable('save');
  419. loadFailedAlert(api);
  420. });
  421. });
  422. }
  423. };
  424. };
  425. var onSubmit = function (templates) {
  426. return function (api) {
  427. var data = api.getData();
  428. findTemplate(templates, data.template).each(function (t) {
  429. getTemplateContent(t).then(function (previewHtml) {
  430. insertTemplate(editor, false, previewHtml);
  431. api.close();
  432. }).catch(function () {
  433. api.disable('save');
  434. loadFailedAlert(api);
  435. });
  436. });
  437. };
  438. };
  439. var openDialog = function (templates) {
  440. var selectBoxItems = createSelectBoxItems(templates);
  441. var buildDialogSpec = function (bodyItems, initialData) {
  442. return {
  443. title: 'Insert Template',
  444. size: 'large',
  445. body: {
  446. type: 'panel',
  447. items: bodyItems
  448. },
  449. initialData: initialData,
  450. buttons: [
  451. {
  452. type: 'cancel',
  453. name: 'cancel',
  454. text: 'Cancel'
  455. },
  456. {
  457. type: 'submit',
  458. name: 'save',
  459. text: 'Save',
  460. primary: true
  461. }
  462. ],
  463. onSubmit: onSubmit(templates),
  464. onChange: onChange(templates, updateDialog)
  465. };
  466. };
  467. var updateDialog = function (dialogApi, template, previewHtml) {
  468. var content = getPreviewContent(editor, previewHtml);
  469. var bodyItems = [
  470. {
  471. type: 'selectbox',
  472. name: 'template',
  473. label: 'Templates',
  474. items: selectBoxItems
  475. },
  476. {
  477. type: 'htmlpanel',
  478. html: '<p aria-live="polite">' + htmlEscape(template.value.description) + '</p>'
  479. },
  480. {
  481. label: 'Preview',
  482. type: 'iframe',
  483. name: 'preview',
  484. sandboxed: false
  485. }
  486. ];
  487. var initialData = {
  488. template: template.text,
  489. preview: content
  490. };
  491. dialogApi.unblock();
  492. dialogApi.redial(buildDialogSpec(bodyItems, initialData));
  493. dialogApi.focus('template');
  494. };
  495. var dialogApi = editor.windowManager.open(buildDialogSpec([], {
  496. template: '',
  497. preview: ''
  498. }));
  499. dialogApi.block('Loading...');
  500. getTemplateContent(templates[0]).then(function (previewHtml) {
  501. updateDialog(dialogApi, templates[0], previewHtml);
  502. }).catch(function () {
  503. updateDialog(dialogApi, templates[0], '');
  504. dialogApi.disable('save');
  505. loadFailedAlert(dialogApi);
  506. });
  507. };
  508. var optTemplates = createTemplates();
  509. optTemplates.each(openDialog);
  510. };
  511. var showDialog = function (editor) {
  512. return function (templates) {
  513. open(editor, templates);
  514. };
  515. };
  516. var register$1 = function (editor) {
  517. editor.ui.registry.addButton('template', {
  518. icon: 'template',
  519. tooltip: 'Insert template',
  520. onAction: createTemplateList(editor.settings, showDialog(editor))
  521. });
  522. editor.ui.registry.addMenuItem('template', {
  523. icon: 'template',
  524. text: 'Insert template...',
  525. onAction: createTemplateList(editor.settings, showDialog(editor))
  526. });
  527. };
  528. function Plugin () {
  529. global.add('template', function (editor) {
  530. register$1(editor);
  531. register(editor);
  532. setup(editor);
  533. });
  534. }
  535. Plugin();
  536. }());