plugin.js 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. /**
  2. * TinyMCE version 6.4.2 (2023-04-26)
  3. */
  4. (function () {
  5. 'use strict';
  6. var global$4 = tinymce.util.Tools.resolve('tinymce.PluginManager');
  7. const hasProto = (v, constructor, predicate) => {
  8. var _a;
  9. if (predicate(v, constructor.prototype)) {
  10. return true;
  11. } else {
  12. return ((_a = v.constructor) === null || _a === void 0 ? void 0 : _a.name) === constructor.name;
  13. }
  14. };
  15. const typeOf = x => {
  16. const t = typeof x;
  17. if (x === null) {
  18. return 'null';
  19. } else if (t === 'object' && Array.isArray(x)) {
  20. return 'array';
  21. } else if (t === 'object' && hasProto(x, String, (o, proto) => proto.isPrototypeOf(o))) {
  22. return 'string';
  23. } else {
  24. return t;
  25. }
  26. };
  27. const isType = type => value => typeOf(value) === type;
  28. const eq = t => a => t === a;
  29. const isString = isType('string');
  30. const isUndefined = eq(undefined);
  31. var global$3 = tinymce.util.Tools.resolve('tinymce.util.Delay');
  32. var global$2 = tinymce.util.Tools.resolve('tinymce.util.LocalStorage');
  33. var global$1 = tinymce.util.Tools.resolve('tinymce.util.Tools');
  34. const fireRestoreDraft = editor => editor.dispatch('RestoreDraft');
  35. const fireStoreDraft = editor => editor.dispatch('StoreDraft');
  36. const fireRemoveDraft = editor => editor.dispatch('RemoveDraft');
  37. const parse = timeString => {
  38. const multiples = {
  39. s: 1000,
  40. m: 60000
  41. };
  42. const parsedTime = /^(\d+)([ms]?)$/.exec(timeString);
  43. return (parsedTime && parsedTime[2] ? multiples[parsedTime[2]] : 1) * parseInt(timeString, 10);
  44. };
  45. const option = name => editor => editor.options.get(name);
  46. const register$1 = editor => {
  47. const registerOption = editor.options.register;
  48. const timeProcessor = value => {
  49. const valid = isString(value);
  50. if (valid) {
  51. return {
  52. value: parse(value),
  53. valid
  54. };
  55. } else {
  56. return {
  57. valid: false,
  58. message: 'Must be a string.'
  59. };
  60. }
  61. };
  62. registerOption('autosave_ask_before_unload', {
  63. processor: 'boolean',
  64. default: true
  65. });
  66. registerOption('autosave_prefix', {
  67. processor: 'string',
  68. default: 'tinymce-autosave-{path}{query}{hash}-{id}-'
  69. });
  70. registerOption('autosave_restore_when_empty', {
  71. processor: 'boolean',
  72. default: false
  73. });
  74. registerOption('autosave_interval', {
  75. processor: timeProcessor,
  76. default: '30s'
  77. });
  78. registerOption('autosave_retention', {
  79. processor: timeProcessor,
  80. default: '20m'
  81. });
  82. };
  83. const shouldAskBeforeUnload = option('autosave_ask_before_unload');
  84. const shouldRestoreWhenEmpty = option('autosave_restore_when_empty');
  85. const getAutoSaveInterval = option('autosave_interval');
  86. const getAutoSaveRetention = option('autosave_retention');
  87. const getAutoSavePrefix = editor => {
  88. const location = document.location;
  89. return editor.options.get('autosave_prefix').replace(/{path}/g, location.pathname).replace(/{query}/g, location.search).replace(/{hash}/g, location.hash).replace(/{id}/g, editor.id);
  90. };
  91. const isEmpty = (editor, html) => {
  92. if (isUndefined(html)) {
  93. return editor.dom.isEmpty(editor.getBody());
  94. } else {
  95. const trimmedHtml = global$1.trim(html);
  96. if (trimmedHtml === '') {
  97. return true;
  98. } else {
  99. const fragment = new DOMParser().parseFromString(trimmedHtml, 'text/html');
  100. return editor.dom.isEmpty(fragment);
  101. }
  102. }
  103. };
  104. const hasDraft = editor => {
  105. var _a;
  106. const time = parseInt((_a = global$2.getItem(getAutoSavePrefix(editor) + 'time')) !== null && _a !== void 0 ? _a : '0', 10) || 0;
  107. if (new Date().getTime() - time > getAutoSaveRetention(editor)) {
  108. removeDraft(editor, false);
  109. return false;
  110. }
  111. return true;
  112. };
  113. const removeDraft = (editor, fire) => {
  114. const prefix = getAutoSavePrefix(editor);
  115. global$2.removeItem(prefix + 'draft');
  116. global$2.removeItem(prefix + 'time');
  117. if (fire !== false) {
  118. fireRemoveDraft(editor);
  119. }
  120. };
  121. const storeDraft = editor => {
  122. const prefix = getAutoSavePrefix(editor);
  123. if (!isEmpty(editor) && editor.isDirty()) {
  124. global$2.setItem(prefix + 'draft', editor.getContent({
  125. format: 'raw',
  126. no_events: true
  127. }));
  128. global$2.setItem(prefix + 'time', new Date().getTime().toString());
  129. fireStoreDraft(editor);
  130. }
  131. };
  132. const restoreDraft = editor => {
  133. var _a;
  134. const prefix = getAutoSavePrefix(editor);
  135. if (hasDraft(editor)) {
  136. editor.setContent((_a = global$2.getItem(prefix + 'draft')) !== null && _a !== void 0 ? _a : '', { format: 'raw' });
  137. fireRestoreDraft(editor);
  138. }
  139. };
  140. const startStoreDraft = editor => {
  141. const interval = getAutoSaveInterval(editor);
  142. global$3.setEditorInterval(editor, () => {
  143. storeDraft(editor);
  144. }, interval);
  145. };
  146. const restoreLastDraft = editor => {
  147. editor.undoManager.transact(() => {
  148. restoreDraft(editor);
  149. removeDraft(editor);
  150. });
  151. editor.focus();
  152. };
  153. const get = editor => ({
  154. hasDraft: () => hasDraft(editor),
  155. storeDraft: () => storeDraft(editor),
  156. restoreDraft: () => restoreDraft(editor),
  157. removeDraft: fire => removeDraft(editor, fire),
  158. isEmpty: html => isEmpty(editor, html)
  159. });
  160. var global = tinymce.util.Tools.resolve('tinymce.EditorManager');
  161. const setup = editor => {
  162. editor.editorManager.on('BeforeUnload', e => {
  163. let msg;
  164. global$1.each(global.get(), editor => {
  165. if (editor.plugins.autosave) {
  166. editor.plugins.autosave.storeDraft();
  167. }
  168. if (!msg && editor.isDirty() && shouldAskBeforeUnload(editor)) {
  169. msg = editor.translate('You have unsaved changes are you sure you want to navigate away?');
  170. }
  171. });
  172. if (msg) {
  173. e.preventDefault();
  174. e.returnValue = msg;
  175. }
  176. });
  177. };
  178. const makeSetupHandler = editor => api => {
  179. api.setEnabled(hasDraft(editor));
  180. const editorEventCallback = () => api.setEnabled(hasDraft(editor));
  181. editor.on('StoreDraft RestoreDraft RemoveDraft', editorEventCallback);
  182. return () => editor.off('StoreDraft RestoreDraft RemoveDraft', editorEventCallback);
  183. };
  184. const register = editor => {
  185. startStoreDraft(editor);
  186. const onAction = () => {
  187. restoreLastDraft(editor);
  188. };
  189. editor.ui.registry.addButton('restoredraft', {
  190. tooltip: 'Restore last draft',
  191. icon: 'restore-draft',
  192. onAction,
  193. onSetup: makeSetupHandler(editor)
  194. });
  195. editor.ui.registry.addMenuItem('restoredraft', {
  196. text: 'Restore last draft',
  197. icon: 'restore-draft',
  198. onAction,
  199. onSetup: makeSetupHandler(editor)
  200. });
  201. };
  202. var Plugin = () => {
  203. global$4.add('autosave', editor => {
  204. register$1(editor);
  205. setup(editor);
  206. register(editor);
  207. editor.on('init', () => {
  208. if (shouldRestoreWhenEmpty(editor) && editor.dom.isEmpty(editor.getBody())) {
  209. restoreDraft(editor);
  210. }
  211. });
  212. return get(editor);
  213. });
  214. };
  215. Plugin();
  216. })();